001/*
002 * Copyright (c) 2026, Oracle and/or its affiliates.
003 *
004 * Licensed under the Universal Permissive License Version 1.0 as shown at
005 * https://oss.oracle.com/licenses/upl/
006 */
007package com.oracle.database.selectai.model;
008
009import com.fasterxml.jackson.annotation.JsonInclude;
010import com.fasterxml.jackson.databind.ObjectMapper;
011import com.fasterxml.jackson.databind.PropertyNamingStrategies;
012
013import java.util.Locale;
014
015/**
016 * Parameters for {@code DBMS_CLOUD_AI.GENERATE_SYNTHETIC_DATA}.
017 * <p>
018 * These parameters control how Select AI samples source table data, uses table
019 * statistics, and schedules parallel requests when generating synthetic data.
020 *
021 * <p>
022 * The SDK performs basic, deterministic validation for values that can be
023 * validated independently of Oracle Database. In particular,
024 * {@code sampleRows} must be between 0 and 100, inclusive, when specified,
025 * and {@code priority} must be one of {@code HIGH}, {@code MEDIUM}, or
026 * {@code LOW}. Invalid values detected by the SDK result in an
027 * {@link IllegalArgumentException}.
028 *
029 * <p>
030 * Database-specific, database-version-specific, and other semantic validation
031 * is delegated to {@code DBMS_CLOUD_AI} and Oracle Database. Therefore, a
032 * parameter value that passes SDK validation may still be rejected by the
033 * database based on the requested synthetic-data operation or other
034 * database-side requirements.
035 *
036 * @see <a href="https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/dbms-cloud-ai-package.html#optional-parameters">
037 *      DBMS_CLOUD_AI synthetic data parameters</a>
038 */
039public final class SyntheticDataParams {
040
041    /** Number of table rows sampled to guide synthetic data generation. */
042    private final Integer sampleRows;
043
044    /** Whether table statistics are used during synthetic data generation. */
045    private final Boolean tableStatistics;
046
047    /**
048     * Priority used to determine the parallelism of synthetic-data generation
049     * requests. Supported values are {@code HIGH}, {@code MEDIUM}, and {@code LOW}.
050     */
051    private final String priority;
052
053    /** Whether table comments are used as context during synthetic data generation. */
054    private final Boolean comments;
055
056    private SyntheticDataParams(Builder builder) {
057        this.sampleRows = builder.sampleRows;
058        this.tableStatistics = builder.tableStatistics;
059        this.priority = builder.priority;
060        this.comments = builder.comments;
061    }
062
063    /**
064     * Returns the number of table rows sampled to guide synthetic data generation.
065     *
066     * @return sample-rows value, or {@code null} when unset
067     */
068    public Integer getSampleRows() {
069        return sampleRows;
070    }
071
072    /**
073     * Returns whether table statistics are used during synthetic data generation.
074     *
075     * @return table-statistics flag, or {@code null} when unset
076     */
077    public Boolean getTableStatistics() {
078        return tableStatistics;
079    }
080
081    /**
082     * Returns the priority used for synthetic data generation.
083     *
084     * @return priority value ({@code HIGH}, {@code MEDIUM}, or {@code LOW}),
085     *         or {@code null} when unset
086     */
087    public String getPriority() {
088        return priority;
089    }
090
091    /**
092     * Returns whether table comments are used as generation context.
093     *
094     * @return comments flag, or {@code null} when unset
095     */
096    public Boolean getComments() {
097        return comments;
098    }
099
100    /**
101     * Serializes the parameter payload using the snake_case names expected by
102     * {@code DBMS_CLOUD_AI}.
103     *
104     * @return JSON representation of this {@code SyntheticDataParams}
105     * @throws IllegalStateException if serialization fails
106     */
107    public String toJson() {
108        try {
109            ObjectMapper mapper = new ObjectMapper();
110            mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
111            mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
112            return mapper.writeValueAsString(this);
113        } catch (Exception e) {
114            throw new IllegalStateException("Failed to serialize SyntheticDataParams", e);
115        }
116    }
117
118    /**
119     * Creates a builder for synthetic data generation parameters.
120     *
121     * @return new builder for constructing {@link SyntheticDataParams}
122     */
123    public static Builder builder() {
124        return new Builder();
125    }
126
127    /**
128     * Priority values accepted by synthetic data generation parameters.
129     */
130    public enum Priority {
131        /** High priority synthetic-data generation. */
132        HIGH,
133        /** Medium priority synthetic-data generation. */
134        MEDIUM,
135        /** Low priority synthetic-data generation. */
136        LOW
137    }
138
139    /**
140     * Builder for {@link SyntheticDataParams}.
141     */
142    public static final class Builder {
143        /** Creates an empty builder. */
144        public Builder() {
145        }
146
147        /** Sample rows value being assembled. */
148        private Integer sampleRows;
149        /** Table statistics flag being assembled. */
150        private Boolean tableStatistics;
151        /** Priority value being assembled. */
152        private String priority;
153        /** Comments flag being assembled. */
154        private Boolean comments;
155
156        /**
157         * Sets the number of table rows sampled to guide synthetic data generation.
158         *
159         * <p>The value must be between 0 and 100, inclusive, when specified.
160         * A value of 0 indicates that no sample rows are used.</p>
161         *
162         * @param sampleRows sample-row value, from 0 through 100, or {@code null}
163         *                   when unset
164         * @return this builder instance
165         * @throws IllegalArgumentException if {@code sampleRows} is less than 0
166         *         or greater than 100
167         */
168        public Builder sampleRows(Integer sampleRows) {
169            if (sampleRows != null && (sampleRows < 0 || sampleRows > 100)) {
170                throw new IllegalArgumentException("sampleRows must be between 0 and 100");
171            }
172            this.sampleRows = sampleRows;
173            return this;
174        }
175
176        /**
177         * Sets whether table statistics should be used during synthetic data
178         * generation.
179         *
180         * @param tableStatistics whether table statistics should be used, or
181         *                        {@code null} when unset
182         * @return this builder instance
183         */
184        public Builder tableStatistics(Boolean tableStatistics) {
185            this.tableStatistics = tableStatistics;
186            return this;
187        }
188
189        /**
190         * Sets the priority used for synthetic data generation.
191         *
192         * <p>The supported values are {@code HIGH}, {@code MEDIUM}, and
193         * {@code LOW}. The comparison is case-insensitive; the value stored by the
194         * builder is normalized to upper case.</p>
195         *
196         * @param priority priority value ({@code HIGH}, {@code MEDIUM}, or
197         *                 {@code LOW}), or {@code null} when unset
198         * @return this builder instance
199         * @throws IllegalArgumentException if {@code priority} is not one of the
200         *         supported values
201         */
202        public Builder priority(String priority) {
203            if (priority != null) {
204                String p = priority.trim().toUpperCase(Locale.ROOT);
205                if (!p.equals("HIGH") && !p.equals("MEDIUM") && !p.equals("LOW")) {
206                    throw new IllegalArgumentException("priority must be HIGH, MEDIUM, or LOW");
207                }
208                this.priority = p;
209            } else {
210                this.priority = null;
211            }
212            return this;
213        }
214
215        /**
216         * Sets the priority used for synthetic data generation.
217         *
218         * @param priority priority value, or {@code null} when unset
219         * @return this builder instance
220         */
221        public Builder priority(Priority priority) {
222            this.priority = priority == null ? null : priority.name();
223            return this;
224        }
225
226        /**
227         * Sets whether table comments should be used as context during synthetic
228         * data generation.
229         *
230         * @param comments whether comments should be used, or {@code null} when unset
231         * @return this builder instance
232         */
233        public Builder comments(Boolean comments) {
234            this.comments = comments;
235            return this;
236        }
237
238        /**
239         * Builds the synthetic data parameter payload.
240         *
241         * <p>SDK-level validation is applied when individual values are set.
242         * Database-specific and semantic validation remains delegated to
243         * {@code DBMS_CLOUD_AI} and Oracle Database.</p>
244         *
245         * @return immutable {@link SyntheticDataParams} instance built from the
246         *         current builder state
247         */
248        public SyntheticDataParams build() {
249            return new SyntheticDataParams(this);
250        }
251    }
252}