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

future-architect / uroborosql / #768

10 Sep 2024 05:58PM UTC coverage: 90.35% (-0.9%) from 91.21%
#768

Pull #332

HidekiSugimoto189
Changed to use slf4j v2.0 API
Also added suppressLogging API
Pull Request #332: Enable per-SQL-ID log suppression (#322)

382 of 585 new or added lines in 32 files covered. (65.3%)

9 existing lines in 7 files now uncovered.

8885 of 9834 relevant lines covered (90.35%)

0.9 hits per line

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

88.46
/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 jp.co.future.uroborosql.context.ExecutionContext;
18
import jp.co.future.uroborosql.dialect.Dialect;
19
import jp.co.future.uroborosql.enums.ForUpdateType;
20
import jp.co.future.uroborosql.event.AfterEntityQueryEvent;
21
import jp.co.future.uroborosql.event.BeforeEntityQueryEvent;
22
import jp.co.future.uroborosql.exception.DataNonUniqueException;
23
import jp.co.future.uroborosql.exception.EntitySqlRuntimeException;
24
import jp.co.future.uroborosql.exception.UroborosqlRuntimeException;
25
import jp.co.future.uroborosql.fluent.SqlEntityQuery;
26
import jp.co.future.uroborosql.log.ServiceLogger;
27
import jp.co.future.uroborosql.mapping.EntityHandler;
28
import jp.co.future.uroborosql.mapping.MappingUtils;
29
import jp.co.future.uroborosql.mapping.TableMetadata;
30
import jp.co.future.uroborosql.utils.BeanAccessor;
31
import jp.co.future.uroborosql.utils.CaseFormat;
32

33
/**
34
 * SqlEntityQuery実装
35
 *
36
 * @param <E> Entity型
37
 * @author ota
38
 */
39
final class SqlEntityQueryImpl<E> extends AbstractExtractionCondition<SqlEntityQuery<E>>
40
                implements SqlEntityQuery<E>, ServiceLogger {
41
        private final EntityHandler<?> entityHandler;
42
        private final Class<? extends E> entityType;
43
        private final List<SortOrder> sortOrders;
44
        private final List<String> optimizerHints;
45
        private final Dialect dialect;
46
        private long limit;
47
        private long offset;
48
        private ForUpdateType forUpdateType;
49
        private int waitSeconds;
50

51
        private final List<String> includeColumns;
52
        private final List<String> excludeColumns;
53

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

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

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

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

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

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

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

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

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

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

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

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

240
                return stream().map(e -> type.cast(BeanAccessor.value(field, e)));
1✔
241
        }
242

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

593
        /**
594
         * {@inheritDoc}
595
         *
596
         * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#forUpdateWait()
597
         */
598
        @Override
599
        public SqlEntityQuery<E> forUpdateWait() {
600
                if (dialect.supportsForUpdateWait()) {
1✔
601
                        return forUpdateWait(agent().getSqlConfig().getSqlAgentProvider().getDefaultForUpdateWaitSeconds());
×
602
                } else if (!agent().getSqlConfig().getSqlAgentProvider().isStrictForUpdateType()
1✔
603
                                && dialect.supportsForUpdate()) {
1✔
604
                        atWarn(LOG)
1✔
605
                                        .log("'FOR UPDATE WAIT' is not supported. Set 'FOR UPDATE' instead.");
1✔
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
                        atWarn(LOG)
1✔
627
                                        .log("'FOR UPDATE WAIT' is not supported. Set 'FOR UPDATE' instead.");
1✔
628
                        this.forUpdateType = ForUpdateType.NORMAL;
1✔
629
                        return this;
1✔
630
                } else {
631
                        throw new UroborosqlRuntimeException("Unsupported for update wait clause.");
1✔
632
                }
633
        }
634

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

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

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

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

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

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

715
                final String getCol() {
716
                        return col;
1✔
717
                }
718

719
                final Order getOrder() {
720
                        return order;
1✔
721
                }
722

723
                final Nulls getNulls() {
724
                        return nulls;
1✔
725
                }
726
        }
727
}
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

© 2025 Coveralls, Inc