• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

future-architect / uroborosql / #764

13 Aug 2024 03:26PM UTC coverage: 91.218% (+0.02%) from 91.197%
#764

Pull #331

HidekiSugimoto189
add oracle v12-23 and Mariadb 5,10 dialect
Pull Request #331: add oracle v12-23 and Mariadb 5,10 dialect

43 of 46 new or added lines in 8 files covered. (93.48%)

288 existing lines in 22 files now uncovered.

8787 of 9633 relevant lines covered (91.22%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.26
/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java
1
/**
2
 * Copyright (c) 2017-present, Future Corporation
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
package jp.co.future.uroborosql;
8

9
import java.sql.SQLException;
10
import java.util.ArrayList;
11
import java.util.HashMap;
12
import java.util.List;
13
import java.util.Optional;
14
import java.util.stream.Collectors;
15
import java.util.stream.Stream;
16

17
import org.slf4j.Logger;
18
import org.slf4j.LoggerFactory;
19

20
import jp.co.future.uroborosql.context.ExecutionContext;
21
import jp.co.future.uroborosql.dialect.Dialect;
22
import jp.co.future.uroborosql.enums.ForUpdateType;
23
import jp.co.future.uroborosql.event.AfterEntityQueryEvent;
24
import jp.co.future.uroborosql.event.BeforeEntityQueryEvent;
25
import jp.co.future.uroborosql.exception.DataNonUniqueException;
26
import jp.co.future.uroborosql.exception.EntitySqlRuntimeException;
27
import jp.co.future.uroborosql.exception.UroborosqlRuntimeException;
28
import jp.co.future.uroborosql.fluent.SqlEntityQuery;
29
import jp.co.future.uroborosql.mapping.EntityHandler;
30
import jp.co.future.uroborosql.mapping.MappingUtils;
31
import jp.co.future.uroborosql.mapping.TableMetadata;
32
import jp.co.future.uroborosql.utils.BeanAccessor;
33
import jp.co.future.uroborosql.utils.CaseFormat;
34

35
/**
36
 * SqlEntityQuery実装
37
 *
38
 * @param <E> Entity型
39
 * @author ota
40
 */
41
final class SqlEntityQueryImpl<E> extends AbstractExtractionCondition<SqlEntityQuery<E>> implements SqlEntityQuery<E> {
42
        /** ロガー */
43
        private static final Logger LOG = LoggerFactory.getLogger("jp.co.future.uroborosql.log");
1✔
44

45
        private final EntityHandler<?> entityHandler;
46
        private final Class<? extends E> entityType;
47
        private final List<SortOrder> sortOrders;
48
        private final List<String> optimizerHints;
49
        private final Dialect dialect;
50
        private long limit;
51
        private long offset;
52
        private ForUpdateType forUpdateType;
53
        private int waitSeconds;
54

55
        private final List<String> includeColumns;
56
        private final List<String> excludeColumns;
57

58
        /**
59
         * Constructor
60
         *
61
         * @param agent SqlAgent
62
         * @param entityHandler EntityHandler
63
         * @param tableMetadata TableMetadata
64
         * @param context ExecutionContext
65
         * @param entityType エンティティタイプ
66
         */
67
        SqlEntityQueryImpl(final SqlAgent agent, final EntityHandler<?> entityHandler, final TableMetadata tableMetadata,
68
                        final ExecutionContext context, final Class<? extends E> entityType) {
69
                super(agent, tableMetadata, context);
1✔
70
                this.entityHandler = entityHandler;
1✔
71
                this.entityType = entityType;
1✔
72
                this.sortOrders = new ArrayList<>();
1✔
73
                this.optimizerHints = new ArrayList<>();
1✔
74
                this.dialect = agent.getSqlConfig().getDialect();
1✔
75
                this.limit = -1;
1✔
76
                this.offset = -1;
1✔
77
                this.forUpdateType = null;
1✔
78
                this.waitSeconds = -1;
1✔
79
                this.includeColumns = new ArrayList<>();
1✔
80
                this.excludeColumns = new ArrayList<>();
1✔
81
        }
1✔
82

83
        /**
84
         * {@inheritDoc}
85
         *
86
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#sqlId(java.lang.String)
87
         */
88
        @Override
89
        public SqlEntityQuery<E> sqlId(final String sqlId) {
UNCOV
90
                context().setSqlId(sqlId);
×
UNCOV
91
                return this;
×
92
        }
93

94
        /**
95
         * {@inheritDoc}
96
         *
97
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#retry(int)
98
         */
99
        @Override
100
        public SqlEntityQuery<E> retry(final int count) {
UNCOV
101
                return retry(count, 0);
×
102
        }
103

104
        /**
105
         * {@inheritDoc}
106
         *
107
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#retry(int, int)
108
         */
109
        @Override
110
        public SqlEntityQuery<E> retry(final int count, final int waitTime) {
UNCOV
111
                context().setMaxRetryCount(count).setRetryWaitTime(waitTime);
×
UNCOV
112
                return this;
×
113
        }
114

115
        /**
116
         * {@inheritDoc}
117
         *
118
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#collect()
119
         */
120
        @Override
121
        public List<E> collect() {
122
                try (var stream = stream()) {
1✔
123
                        return stream.collect(Collectors.toList());
1✔
124
                }
125
        }
126

127
        /**
128
         * {@inheritDoc}
129
         *
130
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#first()
131
         */
132
        @Override
133
        public Optional<E> first() {
134
                try (var stream = stream()) {
1✔
135
                        return stream.findFirst();
1✔
136
                }
137
        }
138

139
        /**
140
         * {@inheritDoc}
141
         *
142
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#one()
143
         */
144
        @Override
145
        public Optional<E> one() {
146
                try (var stream = stream()) {
1✔
147
                        var entities = stream.limit(2).collect(Collectors.toList());
1✔
148
                        if (entities.size() > 1) {
1✔
149
                                throw new DataNonUniqueException("two or more query results.");
1✔
150
                        }
151
                        return entities.stream().findFirst();
1✔
152
                }
153
        }
154

155
        /**
156
         * {@inheritDoc}
157
         *
158
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#stream()
159
         */
160
        @SuppressWarnings("unchecked")
161
        @Override
162
        public Stream<E> stream() {
163
                try {
164
                        var selectClause = context().getSql();
1✔
165
                        if (!includeColumns.isEmpty() || !excludeColumns.isEmpty()) {
1✔
166
                                // 除外対象カラムを取得する
167
                                List<? extends TableMetadata.Column> excludeCols = List.of();
1✔
168
                                if (!includeColumns.isEmpty()) {
1✔
169
                                        excludeCols = tableMetadata().getColumns().stream()
1✔
170
                                                        .filter(col -> !includeColumns.contains(col.getCamelColumnName()))
1✔
171
                                                        .collect(Collectors.toList());
1✔
172
                                        if (excludeCols.size() == tableMetadata().getColumns().size()) {
1✔
173
                                                // includeColumnsに含まれるカラムが1つもselect句に含まれない場合は実行時例外とする
174
                                                throw new UroborosqlRuntimeException("None of the includeColumns matches the column name.");
1✔
175
                                        }
176
                                } else if (!excludeColumns.isEmpty()) {
1✔
177
                                        excludeCols = tableMetadata().getColumns().stream()
1✔
178
                                                        .filter(col -> excludeColumns.contains(col.getCamelColumnName()))
1✔
179
                                                        .collect(Collectors.toList());
1✔
180
                                }
181
                                if (!excludeCols.isEmpty()) {
1✔
182
                                        // 除外対象カラムをselect句から除外する置換処理を行う
183
                                        selectClause = selectClause.replaceAll(excludeCols.stream()
1✔
184
                                                        .map(TableMetadata.Column::getColumnIdentifier)
1✔
185
                                                        .collect(Collectors.joining("|", "\\s*,*\\s+(", ").+")), "");
1✔
186
                                        // SELECT句の直後にカンマがくる場合はそのカンマを除外する
187
                                        selectClause = selectClause.replaceFirst("(SELECT.+\\s*)(,)", "$1 ");
1✔
188
                                }
189
                        }
190
                        var sql = new StringBuilder(selectClause).append(getWhereClause())
1✔
191
                                        .append(getOrderByClause());
1✔
192
                        if (dialect.supportsLimitClause()) {
1✔
193
                                sql.append(dialect.getLimitClause(this.limit, this.offset));
1✔
194
                        }
195
                        if (this.forUpdateType != null) {
1✔
196
                                sql = dialect.addForUpdateClause(sql, this.forUpdateType, this.waitSeconds);
1✔
197
                        }
198
                        if (!this.optimizerHints.isEmpty()) {
1✔
199
                                sql = dialect.addOptimizerHints(sql, this.optimizerHints);
1✔
200
                        }
201
                        context().setSql(sql.toString());
1✔
202

203
                        // EntityQuery実行前イベント発行
204
                        var eventListenerHolder = agent().getSqlConfig().getEventListenerHolder();
1✔
205
                        if (eventListenerHolder.hasBeforeEntityQueryListener()) {
1✔
206
                                var eventObj = new BeforeEntityQueryEvent(context(), null, this.entityType);
1✔
207
                                for (var listener : eventListenerHolder.getBeforeEntityQueryListeners()) {
1✔
208
                                        listener.accept(eventObj);
1✔
209
                                }
1✔
210
                        }
211

212
                        Stream<E> results = this.entityHandler.doSelect(agent(), context(), this.entityType);
1✔
213

214
                        // EntityQuery実行後イベント発行
215
                        if (eventListenerHolder.hasAfterEntityQueryListener()) {
1✔
216
                                var eventObj = new AfterEntityQueryEvent(context(), null, this.entityType, results);
1✔
217
                                for (var listener : eventListenerHolder.getAfterEntityQueryListeners()) {
1✔
218
                                        listener.accept(eventObj);
1✔
219
                                }
1✔
220
                                return (Stream<E>) eventObj.getResults();
1✔
221
                        } else {
222
                                return results;
1✔
223
                        }
UNCOV
224
                } catch (final SQLException ex) {
×
UNCOV
225
                        throw new EntitySqlRuntimeException(context().getSqlKind(), ex);
×
226
                }
227
        }
228

229
        /**
230
         * {@inheritDoc}
231
         *
232
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#select(java.lang.String, java.lang.Class)
233
         */
234
        @Override
235
        public <C> Stream<C> select(final String col, final Class<C> type) {
236
                var fieldName = CaseFormat.CAMEL_CASE.convert(col);
1✔
237
                var field = BeanAccessor.fields(this.entityType).stream()
1✔
238
                                .filter(f -> f.getName().equalsIgnoreCase(fieldName))
1✔
239
                                .findFirst()
1✔
240
                                .orElseThrow(() -> new UroborosqlRuntimeException(
1✔
241
                                                "field:" + fieldName + " not found in " + this.entityType.getSimpleName() + "."));
1✔
242
                includeColumns(fieldName);
1✔
243

244
                return stream().map(e -> type.cast(BeanAccessor.value(field, e)));
1✔
245
        }
246

247
        /**
248
         * 集計関数で集計する元となるSQL文字列を生成する.<br>
249
         * 集計する場合はソートする必要がないので order by が除かれている
250
         *
251
         * @return 集計関数で集計する元となるSQL文字列
252
         */
253
        private StringBuilder aggregationSourceSql() {
254
                var sql = new StringBuilder(context().getSql()).append(getWhereClause());
1✔
255
                if (dialect.supportsLimitClause()) {
1✔
256
                        sql.append(dialect.getLimitClause(this.limit, this.offset));
1✔
257
                }
258
                if (this.forUpdateType != null) {
1✔
259
                        sql = dialect.addForUpdateClause(sql, this.forUpdateType, this.waitSeconds);
1✔
260
                }
261
                return sql;
1✔
262
        }
263

264
        /**
265
         * {@inheritDoc}
266
         *
267
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#count()
268
         */
269
        @Override
270
        public long count() {
271
                return count(null);
1✔
272
        }
273

274
        /**
275
         * {@inheritDoc}
276
         *
277
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#count(java.lang.String)
278
         */
279
        @Override
280
        public long count(final String col) {
281
                var expr = col != null
1✔
282
                                ? tableMetadata().getColumn(CaseFormat.CAMEL_CASE.convert(col)).getColumnIdentifier()
1✔
283
                                : "*";
1✔
284
                var sql = new StringBuilder("select count(").append(expr).append(") from (")
1✔
285
                                .append(System.lineSeparator())
1✔
286
                                .append(aggregationSourceSql())
1✔
287
                                .append(System.lineSeparator())
1✔
288
                                .append(") t_");
1✔
289
                context().setSql(sql.toString());
1✔
290
                try (var rs = agent().query(context())) {
1✔
291
                        rs.next();
1✔
292
                        return rs.getLong(1);
1✔
UNCOV
293
                } catch (final SQLException ex) {
×
UNCOV
294
                        throw new EntitySqlRuntimeException(context().getSqlKind(), ex);
×
295
                }
296
        }
297

298
        /**
299
         * {@inheritDoc}
300
         *
301
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#sum(java.lang.String)
302
         */
303
        @SuppressWarnings("unchecked")
304
        @Override
305
        public <T> T sum(final String col) {
306
                var camelColumnName = CaseFormat.CAMEL_CASE.convert(col);
1✔
307
                var mappingColumn = MappingUtils.getMappingColumn(context().getSchema(), this.entityType, camelColumnName);
1✔
308
                if (!mappingColumn.isNumber()) {
1✔
309
                        throw new UroborosqlRuntimeException("Column is not of type Number. col=" + camelColumnName);
1✔
310
                }
311
                var column = tableMetadata().getColumn(camelColumnName);
1✔
312
                var sql = new StringBuilder("select sum(t_.").append(column.getColumnIdentifier()).append(") as ")
1✔
313
                                .append(column.getColumnIdentifier()).append(" from (")
1✔
314
                                .append(System.lineSeparator())
1✔
315
                                .append(aggregationSourceSql())
1✔
316
                                .append(System.lineSeparator())
1✔
317
                                .append(") t_");
1✔
318
                context().setSql(sql.toString());
1✔
319
                try {
320
                        return (T) mappingColumn
1✔
321
                                        .getValue(this.entityHandler.doSelect(agent(), context(), this.entityType).findFirst().get());
1✔
UNCOV
322
                } catch (final SQLException ex) {
×
UNCOV
323
                        throw new EntitySqlRuntimeException(context().getSqlKind(), ex);
×
324
                }
325
        }
326

327
        /**
328
         * {@inheritDoc}
329
         *
330
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#min(java.lang.String)
331
         */
332
        @SuppressWarnings("unchecked")
333
        @Override
334
        public <T> T min(final String col) {
335
                var camelColumnName = CaseFormat.CAMEL_CASE.convert(col);
1✔
336
                var mappingColumn = MappingUtils.getMappingColumn(context().getSchema(), this.entityType, camelColumnName);
1✔
337
                var column = tableMetadata().getColumn(camelColumnName);
1✔
338
                var sql = new StringBuilder("select min(t_.").append(column.getColumnIdentifier()).append(") as ")
1✔
339
                                .append(column.getColumnIdentifier()).append(" from (")
1✔
340
                                .append(System.lineSeparator())
1✔
341
                                .append(aggregationSourceSql())
1✔
342
                                .append(System.lineSeparator())
1✔
343
                                .append(") t_");
1✔
344
                context().setSql(sql.toString());
1✔
345
                try {
346
                        return (T) mappingColumn
1✔
347
                                        .getValue(this.entityHandler.doSelect(agent(), context(), this.entityType).findFirst().get());
1✔
348
                } catch (SQLException ex) {
×
349
                        throw new EntitySqlRuntimeException(context().getSqlKind(), ex);
×
350
                }
351
        }
352

353
        /**
354
         * {@inheritDoc}
355
         *
356
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#max(java.lang.String)
357
         */
358
        @SuppressWarnings("unchecked")
359
        @Override
360
        public <T> T max(final String col) {
361
                var camelColumnName = CaseFormat.CAMEL_CASE.convert(col);
1✔
362
                var mappingColumn = MappingUtils.getMappingColumn(context().getSchema(), this.entityType, camelColumnName);
1✔
363
                var column = tableMetadata().getColumn(camelColumnName);
1✔
364
                var sql = new StringBuilder("select max(t_.").append(column.getColumnIdentifier()).append(") as ")
1✔
365
                                .append(column.getColumnIdentifier()).append(" from (")
1✔
366
                                .append(System.lineSeparator())
1✔
367
                                .append(aggregationSourceSql())
1✔
368
                                .append(System.lineSeparator())
1✔
369
                                .append(") t_");
1✔
370
                context().setSql(sql.toString());
1✔
371
                try {
372
                        return (T) mappingColumn
1✔
373
                                        .getValue(this.entityHandler.doSelect(agent(), context(), this.entityType).findFirst().get());
1✔
374
                } catch (SQLException ex) {
×
375
                        throw new EntitySqlRuntimeException(context().getSqlKind(), ex);
×
376
                }
377
        }
378

379
        /**
380
         * {@inheritDoc}
381
         *
382
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#exists(java.lang.Runnable)
383
         */
384
        @Override
385
        public void exists(final Runnable runnable) {
386
                var sql = new StringBuilder("select 1 from (")
1✔
387
                                .append(System.lineSeparator())
1✔
388
                                .append(aggregationSourceSql())
1✔
389
                                .append(System.lineSeparator())
1✔
390
                                .append(") t_");
1✔
391
                context().setSql(sql.toString());
1✔
392
                try (var rs = agent().query(context())) {
1✔
393
                        if (rs.next()) {
1✔
UNCOV
394
                                runnable.run();
×
395
                        }
396
                } catch (final SQLException ex) {
×
UNCOV
397
                        throw new EntitySqlRuntimeException(context().getSqlKind(), ex);
×
398
                }
1✔
399
        }
1✔
400

401
        /**
402
         * {@inheritDoc}
403
         *
404
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notExists(java.lang.Runnable)
405
         */
406
        @Override
407
        public void notExists(final Runnable runnable) {
408
                var sql = new StringBuilder("select 1 from (")
1✔
409
                                .append(System.lineSeparator())
1✔
410
                                .append(aggregationSourceSql())
1✔
411
                                .append(System.lineSeparator())
1✔
412
                                .append(") t_");
1✔
413
                context().setSql(sql.toString());
1✔
414
                try (var rs = agent().query(context())) {
1✔
415
                        if (!rs.next()) {
1✔
UNCOV
416
                                runnable.run();
×
417
                        }
418
                } catch (final SQLException ex) {
×
UNCOV
419
                        throw new EntitySqlRuntimeException(context().getSqlKind(), ex);
×
420
                }
1✔
421
        }
1✔
422

423
        /**
424
         * ORDER BY句を生成する
425
         *
426
         * @return ORDER BY句の文字列
427
         */
428
        @SuppressWarnings("unchecked")
429
        private String getOrderByClause() {
430
                var firstFlag = true;
1✔
431
                List<TableMetadata.Column> keys;
432
                var existsSortOrders = new HashMap<TableMetadata.Column, SortOrder>();
1✔
433

434
                if (this.sortOrders.isEmpty()) {
1✔
435
                        // ソート条件の指定がない場合は主キーでソートする
436
                        keys = (List<TableMetadata.Column>) tableMetadata().getKeyColumns();
1✔
437
                        for (var key : keys) {
1✔
438
                                existsSortOrders.put(key, new SortOrder(key.getCamelColumnName(), Order.ASCENDING));
1✔
439
                        }
1✔
440
                } else {
441
                        // ソート条件の指定がある場合は指定されたカラムでソートする
442
                        keys = new ArrayList<>();
1✔
443
                        for (var sortOrder : sortOrders) {
1✔
444
                                for (var metaCol : tableMetadata().getColumns()) {
1✔
445
                                        if (sortOrder.getCol().equals(metaCol.getCamelColumnName())) {
1✔
446
                                                keys.add(metaCol);
1✔
447
                                                existsSortOrders.put(metaCol, sortOrder);
1✔
448
                                                break;
1✔
449
                                        }
450
                                }
1✔
451
                        }
1✔
452
                }
453

454
                if (!keys.isEmpty()) {
1✔
455
                        var sql = new StringBuilder();
1✔
456
                        sql.append("ORDER BY").append(System.lineSeparator());
1✔
457
                        firstFlag = true;
1✔
458
                        for (final TableMetadata.Column key : keys) {
1✔
459
                                var sortOrder = existsSortOrders.get(key);
1✔
460
                                sql.append("\t");
1✔
461
                                if (firstFlag) {
1✔
462
                                        sql.append("  ");
1✔
463
                                        firstFlag = false;
1✔
464
                                } else {
465
                                        sql.append(", ");
1✔
466
                                }
467
                                sql.append(key.getColumnIdentifier()).append(" ").append(sortOrder.getOrder().toString());
1✔
468
                                if (dialect.supportsNullValuesOrdering()) {
1✔
469
                                        sql.append(" ").append(sortOrder.getNulls().toString());
1✔
470
                                }
471
                                sql.append(System.lineSeparator());
1✔
472
                        }
1✔
473
                        return sql.toString();
1✔
474
                } else {
475
                        return "";
1✔
476
                }
477
        }
478

479
        /**
480
         * {@inheritDoc}
481
         *
482
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#asc(java.lang.String[])
483
         */
484
        @Override
485
        public SqlEntityQuery<E> asc(final String... cols) {
486
                for (var col : cols) {
1✔
487
                        this.sortOrders.add(new SortOrder(col, Order.ASCENDING));
1✔
488
                }
489
                return this;
1✔
490
        }
491

492
        /**
493
         * {@inheritDoc}
494
         *
495
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#asc(java.lang.String, jp.co.future.uroborosql.fluent.SqlEntityQuery.Nulls)
496
         */
497
        @Override
498
        public SqlEntityQuery<E> asc(final String col, final Nulls nulls) {
499
                this.sortOrders.add(new SortOrder(col, Order.ASCENDING, nulls));
1✔
500
                return this;
1✔
501
        }
502

503
        /**
504
         * {@inheritDoc}
505
         *
506
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#desc(java.lang.String[])
507
         */
508
        @Override
509
        public SqlEntityQuery<E> desc(final String... cols) {
510
                for (var col : cols) {
1✔
511
                        this.sortOrders.add(new SortOrder(col, Order.DESCENDING));
1✔
512
                }
513
                return this;
1✔
514
        }
515

516
        /**
517
         * {@inheritDoc}
518
         *
519
        s         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#desc(java.lang.String, jp.co.future.uroborosql.fluent.SqlEntityQuery.Nulls)
520
         */
521
        @Override
522
        public SqlEntityQuery<E> desc(final String col, final Nulls nulls) {
523
                this.sortOrders.add(new SortOrder(col, Order.DESCENDING, nulls));
1✔
524
                return this;
1✔
525
        }
526

527
        /**
528
         * {@inheritDoc}
529
         *
530
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#limit(long)
531
         */
532
        @Override
533
        public SqlEntityQuery<E> limit(final long limit) {
534
                if (!dialect.supportsLimitClause()) {
1✔
UNCOV
535
                        throw new UroborosqlRuntimeException("Unsupported limit clause.");
×
536
                }
537
                this.limit = limit;
1✔
538
                return this;
1✔
539
        }
540

541
        /**
542
         * {@inheritDoc}
543
         *
544
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#offset(long)
545
         */
546
        @Override
547
        public SqlEntityQuery<E> offset(final long offset) {
548
                if (!dialect.supportsLimitClause()) {
1✔
UNCOV
549
                        throw new UroborosqlRuntimeException("Unsupported offset clause.");
×
550
                }
551
                this.offset = offset;
1✔
552
                return this;
1✔
553
        }
554

555
        /**
556
         * {@inheritDoc}
557
         *
558
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#forUpdate()
559
         */
560
        @Override
561
        public SqlEntityQuery<E> forUpdate() {
562
                if (dialect.supportsForUpdate()) {
1✔
563
                        this.forUpdateType = ForUpdateType.NORMAL;
1✔
564
                        return this;
1✔
565
                } else {
UNCOV
566
                        throw new UroborosqlRuntimeException("Unsupported for update clause.");
×
567
                }
568
        }
569

570
        /**
571
         * {@inheritDoc}
572
         *
573
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#forUpdateNoWait()
574
         */
575
        @Override
576
        public SqlEntityQuery<E> forUpdateNoWait() {
577
                if (dialect.supportsForUpdateNoWait()) {
1✔
UNCOV
578
                        this.forUpdateType = ForUpdateType.NOWAIT;
×
UNCOV
579
                        return this;
×
580
                } else if (!agent().getSqlConfig().getSqlAgentProvider().isStrictForUpdateType()
1✔
581
                                && dialect.supportsForUpdate()) {
1✔
582
                        if (LOG.isWarnEnabled()) {
1✔
583
                                LOG.warn("'FOR UPDATE NOWAIT' is not supported. Set 'FOR UPDATE' instead.");
1✔
584
                        }
585
                        this.forUpdateType = ForUpdateType.NORMAL;
1✔
586
                        return this;
1✔
587
                } else {
588
                        throw new UroborosqlRuntimeException("Unsupported for update nowait clause.");
1✔
589
                }
590
        }
591

592
        /**
593
         * {@inheritDoc}
594
         *
595
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#forUpdateWait()
596
         */
597
        @Override
598
        public SqlEntityQuery<E> forUpdateWait() {
599
                if (dialect.supportsForUpdateWait()) {
1✔
UNCOV
600
                        return forUpdateWait(agent().getSqlConfig().getSqlAgentProvider().getDefaultForUpdateWaitSeconds());
×
601
                } else if (!agent().getSqlConfig().getSqlAgentProvider().isStrictForUpdateType()
1✔
602
                                && dialect.supportsForUpdate()) {
1✔
603
                        if (LOG.isWarnEnabled()) {
1✔
604
                                LOG.warn("'FOR UPDATE WAIT' is not supported. Set 'FOR UPDATE' instead.");
1✔
605
                        }
606
                        this.forUpdateType = ForUpdateType.NORMAL;
1✔
607
                        return this;
1✔
608
                } else {
609
                        throw new UroborosqlRuntimeException("Unsupported for update wait clause.");
1✔
610
                }
611
        }
612

613
        /**
614
         * {@inheritDoc}
615
         *
616
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#forUpdateWait(int)
617
         */
618
        @Override
619
        public SqlEntityQuery<E> forUpdateWait(final int waitSeconds) {
620
                if (dialect.supportsForUpdateWait()) {
1✔
621
                        this.forUpdateType = ForUpdateType.WAIT;
×
622
                        this.waitSeconds = waitSeconds;
×
623
                        return this;
×
624
                } else if (!agent().getSqlConfig().getSqlAgentProvider().isStrictForUpdateType()
1✔
625
                                && dialect.supportsForUpdate()) {
1✔
626
                        if (LOG.isWarnEnabled()) {
1✔
627
                                LOG.warn("'FOR UPDATE WAIT' is not supported. Set 'FOR UPDATE' instead.");
1✔
628
                        }
629
                        this.forUpdateType = ForUpdateType.NORMAL;
1✔
630
                        return this;
1✔
631
                } else {
632
                        throw new UroborosqlRuntimeException("Unsupported for update wait clause.");
1✔
633
                }
634
        }
635

636
        /**
637
         * {@inheritDoc}
638
         *
639
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#hint(java.lang.String)
640
         */
641
        @Override
642
        public SqlEntityQuery<E> hint(final String hint) {
643
                if (dialect.supportsOptimizerHints()) {
1✔
644
                        this.optimizerHints.add(hint);
1✔
645
                } else {
646
                        if (LOG.isWarnEnabled()) {
×
UNCOV
647
                                LOG.warn("Optimizer Hints is not supported.");
×
648
                        }
649
                }
650
                return this;
1✔
651
        }
652

653
        /**
654
         * {@inheritDoc}
655
         *
656
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#includeColumns(java.lang.String[])
657
         */
658
        @Override
659
        public SqlEntityQuery<E> includeColumns(final String... cols) {
660
                if (cols != null && cols.length != 0) {
1✔
661
                        for (var col : cols) {
1✔
662
                                includeColumns.add(CaseFormat.CAMEL_CASE.convert(col));
1✔
663
                        }
664
                }
665
                return this;
1✔
666
        }
667

668
        /**
669
         * {@inheritDoc}
670
         *
671
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#excludeColumns(java.lang.String[])
672
         */
673
        @Override
674
        public SqlEntityQuery<E> excludeColumns(final String... cols) {
675
                if (cols != null && cols.length != 0) {
1✔
676
                        for (var col : cols) {
1✔
677
                                excludeColumns.add(CaseFormat.CAMEL_CASE.convert(col));
1✔
678
                        }
679
                }
680
                return this;
1✔
681
        }
682

683
        /**
684
         * Sort Order
685
         */
686
        private static class SortOrder {
687
                private final String col;
688
                private final Order order;
689
                private final Nulls nulls;
690

691
                /**
692
                 * Constructor
693
                 *
694
                 * @param col sort column name (camelCase)
695
                 * @param order {@link Order}
696
                 */
697
                SortOrder(final String col, final Order order) {
698
                        this(col, order, Nulls.LAST);
1✔
699
                }
1✔
700

701
                /**
702
                 * Constructor
703
                 *
704
                 * @param col sort column name (camelCase)
705
                 * @param order {@link Order}
706
                 * @param nulls {@link Nulls}
707
                 */
708
                SortOrder(final String col, final Order order, final Nulls nulls) {
1✔
709
                        if (col == null) {
1✔
UNCOV
710
                                throw new UroborosqlRuntimeException("argument col is required.");
×
711
                        }
712
                        this.col = CaseFormat.CAMEL_CASE.convert(col);
1✔
713
                        this.order = order != null ? order : Order.ASCENDING;
1✔
714
                        this.nulls = nulls != null ? nulls : Nulls.LAST;
1✔
715
                }
1✔
716

717
                final String getCol() {
718
                        return col;
1✔
719
                }
720

721
                final Order getOrder() {
722
                        return order;
1✔
723
                }
724

725
                final Nulls getNulls() {
726
                        return nulls;
1✔
727
                }
728
        }
729
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc