001/*
002 * Copyright 2015-2022 Transmogrify LLC, 2022-2023 Revetware LLC.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.pyranid;
018
019import javax.annotation.Nonnull;
020import javax.annotation.Nullable;
021import javax.annotation.concurrent.NotThreadSafe;
022import javax.annotation.concurrent.ThreadSafe;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.Collections;
026import java.util.List;
027import java.util.Objects;
028import java.util.Optional;
029import java.util.stream.Collectors;
030
031import static java.lang.String.format;
032import static java.util.Objects.requireNonNull;
033
034/**
035 * Data that represents a SQL statement.
036 *
037 * @author <a href="https://www.revetkn.com">Mark Allen</a>
038 * @since 2.0.0
039 */
040@ThreadSafe
041public class StatementContext<T> {
042        @Nonnull
043        private final Statement statement;
044        @Nonnull
045        private final List<Object> parameters;
046        @Nullable
047        private final Class<T> resultSetRowType;
048
049        protected StatementContext(@Nonnull Builder builder) {
050                requireNonNull(builder);
051
052                this.statement = builder.statement;
053                this.parameters = builder.parameters == null ? List.of() : Collections.unmodifiableList(builder.parameters);
054                this.resultSetRowType = builder.resultSetRowType;
055        }
056
057        @Override
058        public int hashCode() {
059                return Objects.hash(getStatement(), getParameters(), getResultSetRowType());
060        }
061
062        @Override
063        public boolean equals(Object object) {
064                if (this == object)
065                        return true;
066
067                if (!(object instanceof StatementContext))
068                        return false;
069
070                StatementContext statementContext = (StatementContext) object;
071
072                return Objects.equals(statementContext.getStatement(), getStatement())
073                                && Objects.equals(statementContext.getParameters(), getParameters())
074                                && Objects.equals(statementContext.getResultSetRowType(), getResultSetRowType());
075        }
076
077        @Override
078        public String toString() {
079                List<String> components = new ArrayList<>(3);
080
081                components.add(format("statement=%s", getStatement()));
082
083                if (getParameters().size() > 0)
084                        components.add(format("parameters=%s", getParameters()));
085
086                Class<T> resultSetRowType = getResultSetRowType().orElse(null);
087
088                if (resultSetRowType != null)
089                        components.add(format("resultSetRowType=%s", resultSetRowType));
090
091                return format("%s{%s}", getClass().getSimpleName(), components.stream().collect(Collectors.joining(", ")));
092        }
093
094        @Nonnull
095        public Statement getStatement() {
096                return this.statement;
097        }
098
099        @Nonnull
100        public List<Object> getParameters() {
101                return this.parameters;
102        }
103
104        @Nonnull
105        public Optional<Class<T>> getResultSetRowType() {
106                return Optional.ofNullable(this.resultSetRowType);
107        }
108
109        /**
110         * Builder used to construct instances of {@link StatementContext}.
111         * <p>
112         * This class is intended for use by a single thread.
113         *
114         * @author <a href="https://www.revetkn.com">Mark Allen</a>
115         * @since 2.0.0
116         */
117        @NotThreadSafe
118        public static class Builder<T> {
119                @Nonnull
120                private final Statement statement;
121                @Nullable
122                private List<Object> parameters;
123                @Nullable
124                private Class<T> resultSetRowType;
125
126                public Builder(@Nonnull Statement statement) {
127                        requireNonNull(statement);
128                        this.statement = statement;
129                }
130
131                @Nonnull
132                public Builder parameters(@Nullable List<Object> parameters) {
133                        this.parameters = parameters;
134                        return this;
135                }
136
137                @Nonnull
138                public Builder parameters(@Nullable Object... parameters) {
139                        this.parameters = parameters == null ? null : Arrays.asList(parameters);
140                        return this;
141                }
142
143                @Nonnull
144                public Builder resultSetRowType(Class<T> resultSetRowType) {
145                        this.resultSetRowType = resultSetRowType;
146                        return this;
147                }
148
149                @Nonnull
150                public StatementContext build() {
151                        return new StatementContext(this);
152                }
153        }
154}