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

torand / FasterSQL / 13591799490

28 Feb 2025 03:59PM UTC coverage: 65.237% (-1.3%) from 66.563%
13591799490

push

github

web-flow
Merge pull request #14 from torand/having-support

feat: supporting the HAVING clause + IS NULL operator now supports an…

214 of 408 branches covered (52.45%)

Branch coverage included in aggregate %.

273 of 389 new or added lines in 69 files covered. (70.18%)

3 existing lines in 3 files now uncovered.

1079 of 1574 relevant lines covered (68.55%)

3.68 hits per line

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

78.72
/src/main/java/io/github/torand/fastersql/statement/DeleteStatement.java
1
/*
2
 * Copyright (c) 2024 Tore Eide Andersen
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, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package io.github.torand.fastersql.statement;
17

18
import io.github.torand.fastersql.Column;
19
import io.github.torand.fastersql.Context;
20
import io.github.torand.fastersql.Table;
21
import io.github.torand.fastersql.predicate.OptionalPredicate;
22
import io.github.torand.fastersql.predicate.Predicate;
23

24
import java.util.Collection;
25
import java.util.List;
26
import java.util.function.Supplier;
27
import java.util.stream.Stream;
28

29
import static io.github.torand.fastersql.Command.DELETE;
30
import static io.github.torand.fastersql.statement.Helpers.unwrapSuppliers;
31
import static io.github.torand.fastersql.util.collection.CollectionHelper.asList;
32
import static io.github.torand.fastersql.util.collection.CollectionHelper.concat;
33
import static io.github.torand.fastersql.util.collection.CollectionHelper.nonEmpty;
34
import static io.github.torand.fastersql.util.collection.CollectionHelper.streamSafely;
35
import static io.github.torand.fastersql.util.contract.Requires.requireNonEmpty;
36
import static java.util.Objects.isNull;
37
import static java.util.Objects.requireNonNull;
38
import static java.util.stream.Collectors.joining;
39

40
public class DeleteStatement extends PreparableStatement {
41
    private final Table<?> fromTable;
42
    private final List<Predicate> predicates;
43

44
    DeleteStatement(Table<?> table, Collection<Predicate> predicates) {
2✔
45
        this.fromTable = requireNonNull(table, "No table specified");
6✔
46
        this.predicates = asList(predicates);
4✔
47
    }
1✔
48

49
    public DeleteStatement where(Predicate... predicates) {
50
        requireNonEmpty(predicates, "No predicates specified");
6✔
51
        List<Predicate> concatenated = concat(this.predicates, predicates);
5✔
52
        return new DeleteStatement(fromTable, concatenated);
7✔
53
    }
54

55
    /**
56
     * Same as other method of same name, but only adds to the where clause predicates that are present.
57
     * @param maybePredicates the predicates that may be present or not
58
     * @return updated statement, for method chaining
59
     */
60
    public final DeleteStatement where(OptionalPredicate... maybePredicates) {
61
        requireNonEmpty(maybePredicates, "No optional predicates specified");
×
62
        List<Predicate> concatenated = concat(this.predicates, OptionalPredicate.unwrap(maybePredicates));
×
63
        return new DeleteStatement(fromTable, concatenated);
×
64
    }
65

66
    /**
67
     * Adds one or more predicates to the where clause, if a predicate is true.
68
     * @param condition the condition that must be true for predicates to be added
69
     * @param predicateSuppliers the suppliers providing predicates to add
70
     * @return updated statement, for method chaining
71
     */
72
    @SafeVarargs
73
    public final DeleteStatement whereIf(boolean condition, Supplier<Predicate>... predicateSuppliers) {
74
        requireNonEmpty(predicateSuppliers, "No predicate suppliers specified");
6✔
75
        if (condition) {
2!
76
            List<Predicate> concatenated = concat(this.predicates, unwrapSuppliers(predicateSuppliers));
6✔
77
            return new DeleteStatement(fromTable, concatenated);
7✔
78
        }
79
        return this;
×
80
    }
81

82
    @Override
83
    String sql(Context context) {
84
        final Context localContext = context.withCommand(DELETE);
4✔
85
        validate();
2✔
86

87
        StringBuilder sb = new StringBuilder();
4✔
88
        sb.append("delete from ");
4✔
89
        sb.append(fromTable.sql(localContext));
7✔
90

91
        if (nonEmpty(predicates)) {
4!
92
            sb.append(" where ");
4✔
93
            sb.append(streamSafely(predicates)
8✔
94
                .map(p -> p.sql(localContext))
6✔
95
                .collect(joining(" and ")));
3✔
96
        }
97

98
        return sb.toString();
3✔
99
    }
100

101
    @Override
102
    List<Object> params(Context context) {
103
        return streamSafely(predicates)
6✔
104
            .flatMap(p -> p.params(context))
5✔
105
            .toList();
1✔
106
    }
107

108
    private void validate() {
109
        if (isNull(fromTable)) {
4!
110
            throw new IllegalStateException("No FROM clause specified");
×
111
        }
112

113
        // TODO: Verify that deleteTables is subset of fromTables
114

115
        validateColumnTableRelations(streamSafely(predicates).flatMap(Predicate::columnRefs));
7✔
116
    }
1✔
117

118
    private void validateColumnTableRelations(Stream<Column> columns) {
119
        columns
3✔
120
            .filter(c -> !fromTable.name().equalsIgnoreCase(c.table().name()))
11!
121
            .findFirst()
2✔
122
            .ifPresent(c -> {
1✔
NEW
123
                throw new IllegalStateException("Column " + c.name() + " belongs to table " + c.table().name() + ", but table is not specified in the FROM clause");
×
124
            });
125
    }
1✔
126
}
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