001package gudusoft.gsqlparser.catalog.runtime;
002
003import gudusoft.gsqlparser.EDbVendor;
004import gudusoft.gsqlparser.catalog.input.CatalogLoadingMode;
005import gudusoft.gsqlparser.catalog.input.model.DefaultsConfig;
006
007import java.util.Collections;
008import java.util.EnumSet;
009import java.util.LinkedHashSet;
010import java.util.Objects;
011import java.util.Set;
012
013/**
014 * Bounded request handed to {@link CatalogProvider#snapshot(CatalogQuery)}.
015 *
016 * <p>Plan ยง7.2. {@code requestedNames} empty means "all" (eager); non-empty restricts to
017 * the explicit set (lazy). Caps from {@code CatalogLoadOptions} are folded in before the
018 * query reaches the provider. {@link #requestedKinds()} empty means "all kinds".</p>
019 */
020public final class CatalogQuery {
021
022    private final EDbVendor vendor;
023    private final DefaultsConfig defaults;
024    private final CatalogSearchPath searchPath;
025    private final Set<CatalogQualifiedName> requestedNames;
026    private final Set<CatalogObjectKind> requestedKinds;
027    private final boolean includeColumns;
028    private final boolean includeViews;
029    private final boolean includeRoutines;
030    private final CatalogLoadingMode loadingMode;
031    private final long ttlMillis;
032    private final int maxFetchesPerAnalysis;
033
034    private CatalogQuery(Builder b) {
035        if (b.vendor == null) {
036            throw new IllegalArgumentException("CatalogQuery.vendor is required");
037        }
038        if (b.ttlMillis < 0) {
039            throw new IllegalArgumentException(
040                "CatalogQuery.ttlMillis must be >= 0 (got " + b.ttlMillis + ")");
041        }
042        if (b.maxFetchesPerAnalysis < 0) {
043            throw new IllegalArgumentException(
044                "CatalogQuery.maxFetchesPerAnalysis must be >= 0 (got "
045                    + b.maxFetchesPerAnalysis + ")");
046        }
047        this.vendor = b.vendor;
048        this.defaults = b.defaults != null ? b.defaults : DefaultsConfig.empty();
049        this.searchPath = b.searchPath != null ? b.searchPath : CatalogSearchPath.empty();
050        this.requestedNames = Collections.unmodifiableSet(
051            new LinkedHashSet<CatalogQualifiedName>(b.requestedNames));
052        this.requestedKinds = b.requestedKinds.isEmpty()
053            ? Collections.<CatalogObjectKind>emptySet()
054            : Collections.unmodifiableSet(EnumSet.copyOf(b.requestedKinds));
055        this.includeColumns = b.includeColumns;
056        this.includeViews = b.includeViews;
057        this.includeRoutines = b.includeRoutines;
058        this.loadingMode = b.loadingMode != null ? b.loadingMode : CatalogLoadingMode.EAGER;
059        this.ttlMillis = b.ttlMillis;
060        this.maxFetchesPerAnalysis = b.maxFetchesPerAnalysis;
061    }
062
063    public static Builder builder() {
064        return new Builder();
065    }
066
067    public EDbVendor vendor() {
068        return vendor;
069    }
070
071    public DefaultsConfig defaults() {
072        return defaults;
073    }
074
075    public CatalogSearchPath searchPath() {
076        return searchPath;
077    }
078
079    public Set<CatalogQualifiedName> requestedNames() {
080        return requestedNames;
081    }
082
083    public Set<CatalogObjectKind> requestedKinds() {
084        return requestedKinds;
085    }
086
087    public boolean includeColumns() {
088        return includeColumns;
089    }
090
091    public boolean includeViews() {
092        return includeViews;
093    }
094
095    public boolean includeRoutines() {
096        return includeRoutines;
097    }
098
099    public CatalogLoadingMode loadingMode() {
100        return loadingMode;
101    }
102
103    public long ttlMillis() {
104        return ttlMillis;
105    }
106
107    public int maxFetchesPerAnalysis() {
108        return maxFetchesPerAnalysis;
109    }
110
111    @Override
112    public boolean equals(Object o) {
113        if (this == o) return true;
114        if (!(o instanceof CatalogQuery)) return false;
115        CatalogQuery that = (CatalogQuery) o;
116        return includeColumns == that.includeColumns
117            && includeViews == that.includeViews
118            && includeRoutines == that.includeRoutines
119            && ttlMillis == that.ttlMillis
120            && maxFetchesPerAnalysis == that.maxFetchesPerAnalysis
121            && vendor == that.vendor
122            && defaults.equals(that.defaults)
123            && searchPath.equals(that.searchPath)
124            && requestedNames.equals(that.requestedNames)
125            && requestedKinds.equals(that.requestedKinds)
126            && loadingMode == that.loadingMode;
127    }
128
129    @Override
130    public int hashCode() {
131        return Objects.hash(vendor, defaults, searchPath, requestedNames, requestedKinds,
132            includeColumns, includeViews, includeRoutines, loadingMode, ttlMillis,
133            maxFetchesPerAnalysis);
134    }
135
136    @Override
137    public String toString() {
138        return "CatalogQuery{vendor=" + vendor
139            + ", names=" + requestedNames.size()
140            + ", kinds=" + requestedKinds
141            + ", mode=" + loadingMode + '}';
142    }
143
144    public static final class Builder {
145
146        private EDbVendor vendor;
147        private DefaultsConfig defaults;
148        private CatalogSearchPath searchPath;
149        private final Set<CatalogQualifiedName> requestedNames = new LinkedHashSet<CatalogQualifiedName>();
150        private final Set<CatalogObjectKind> requestedKinds = EnumSet.noneOf(CatalogObjectKind.class);
151        private boolean includeColumns = true;
152        private boolean includeViews = true;
153        private boolean includeRoutines = true;
154        private CatalogLoadingMode loadingMode;
155        private long ttlMillis;
156        private int maxFetchesPerAnalysis;
157
158        private Builder() {
159        }
160
161        public Builder vendor(EDbVendor v) {
162            this.vendor = v;
163            return this;
164        }
165
166        public Builder defaults(DefaultsConfig v) {
167            this.defaults = v;
168            return this;
169        }
170
171        public Builder searchPath(CatalogSearchPath v) {
172            this.searchPath = v;
173            return this;
174        }
175
176        public Builder addRequestedName(CatalogQualifiedName v) {
177            if (v == null) {
178                throw new IllegalArgumentException("CatalogQuery requested name may not be null");
179            }
180            this.requestedNames.add(v);
181            return this;
182        }
183
184        public Builder addRequestedKind(CatalogObjectKind v) {
185            if (v == null) {
186                throw new IllegalArgumentException("CatalogQuery requested kind may not be null");
187            }
188            this.requestedKinds.add(v);
189            return this;
190        }
191
192        public Builder includeColumns(boolean v) {
193            this.includeColumns = v;
194            return this;
195        }
196
197        public Builder includeViews(boolean v) {
198            this.includeViews = v;
199            return this;
200        }
201
202        public Builder includeRoutines(boolean v) {
203            this.includeRoutines = v;
204            return this;
205        }
206
207        public Builder loadingMode(CatalogLoadingMode v) {
208            this.loadingMode = v;
209            return this;
210        }
211
212        public Builder ttlMillis(long v) {
213            this.ttlMillis = v;
214            return this;
215        }
216
217        public Builder maxFetchesPerAnalysis(int v) {
218            this.maxFetchesPerAnalysis = v;
219            return this;
220        }
221
222        public CatalogQuery build() {
223            return new CatalogQuery(this);
224        }
225    }
226}