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;
011
012import java.util.ArrayList;
013import java.util.List;
014
015/**
016 * Request object for generating synthetic data for multiple database objects.
017 * <p>
018 * A batch request groups multiple {@link SyntheticDataObjectList} descriptors
019 * together with shared {@link SyntheticDataParams} used for the synthetic data
020 * generation operation.
021 * <p>
022 * This model represents the batch form of
023 * {@code DBMS_CLOUD_AI.GENERATE_SYNTHETIC_DATA}, where target objects are sent
024 * through the {@code object_list} CLOB parameter and shared generation options
025 * are sent through the {@code params} CLOB parameter.
026 *
027 * <p>
028 * The SDK performs basic, deterministic validation where the constraint can
029 * be evaluated independently of Oracle Database. Each object descriptor must
030 * be non-null, and the batch must contain at least one object descriptor.
031 * Invalid values detected by the SDK result in an
032 * {@link IllegalArgumentException}.
033 *
034 * <p>
035 * Database-specific, database-version-specific, and other semantic validation
036 * is delegated to {@code DBMS_CLOUD_AI} and Oracle Database. Therefore, a batch
037 * request that passes SDK validation may still be rejected by the database
038 * based on the selected profile, object descriptors, generation parameters,
039 * or other database-side requirements.
040 *
041 * @see SyntheticDataObjectList
042 * @see SyntheticDataParams
043 * @see <a href="https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/dbms-cloud-ai-package.html">
044 *      DBMS_CLOUD_AI.GENERATE_SYNTHETIC_DATA reference</a>
045 */
046public final class SyntheticDataBatchRequest {
047
048    /** Ordered collection of target database object descriptors. */
049    private final List<SyntheticDataObjectList> objectList;
050
051    /** Synthetic data generation parameters shared by the batch. */
052    private final SyntheticDataParams params;
053
054    private SyntheticDataBatchRequest(Builder builder) {
055        this.objectList = List.copyOf(builder.objectList);
056        this.params = builder.params;
057    }
058
059    /**
060     * Returns the object descriptors serialized as a JSON array for
061     * {@code DBMS_CLOUD_AI.GENERATE_SYNTHETIC_DATA}.
062     *
063     * @return JSON array representing the batch object list
064     * @throws IllegalStateException if the object list cannot be serialized
065     */
066    public String getObjectListJson() {
067        try {
068            ObjectMapper mapper = new ObjectMapper();
069            mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
070            return mapper.writeValueAsString(objectList);
071        } catch (Exception e) {
072            throw new IllegalStateException("Failed to serialize SyntheticDataBatchRequest.objectList", e);
073        }
074    }
075
076    /**
077     * Returns the shared synthetic data generation parameters serialized as JSON.
078     *
079     * @return JSON representation of {@link SyntheticDataParams}, or {@code null}
080     *         when no parameters are configured
081     */
082    public String getParamsJson() {
083        return params == null ? null : params.toJson();
084    }
085
086    /**
087     * Returns the synthetic data generation parameters shared by the batch.
088     *
089     * @return generation parameters, or {@code null} when not set
090     */
091    public SyntheticDataParams getParams() {
092        return params;
093    }
094
095    /**
096     * Returns the target database object descriptors.
097     *
098     * @return immutable list of target object descriptors
099     */
100    public List<SyntheticDataObjectList> getObjectList() {
101        return objectList;
102    }
103
104    /**
105     * Creates a builder for a batch synthetic-data request.
106     *
107     * @return new builder for constructing a batch request
108     */
109    public static Builder builder() {
110        return new Builder();
111    }
112
113    /**
114     * Builder for {@link SyntheticDataBatchRequest}.
115     */
116    public static final class Builder {
117        /** Target object descriptors being assembled for the batch. */
118        private final List<SyntheticDataObjectList> objectList =
119                new ArrayList<>();
120
121        /** Shared synthetic data generation parameters being assembled. */
122        private SyntheticDataParams params;
123
124        private Builder() {
125        }
126
127        /**
128         * Adds a target object descriptor to the batch.
129         *
130         * @param object target object descriptor
131         * @return this builder instance
132         * @throws IllegalArgumentException if {@code object} is null
133         */
134        public Builder addObject(SyntheticDataObjectList object) {
135            if (object == null) {
136                throw new IllegalArgumentException("object must not be null");
137            }
138            this.objectList.add(object);
139            return this;
140        }
141
142        /**
143         * Sets the synthetic data generation parameters shared by the batch.
144         *
145         * @param params synthetic data generation parameters
146         * @return this builder instance
147         */
148        public Builder params(SyntheticDataParams params) {
149            this.params = params;
150            return this;
151        }
152
153        /**
154         * Builds the batch synthetic-data request.
155         *
156         * <p>The SDK requires at least one target object descriptor in the batch.
157         * Database-specific validation of the object descriptors and generation
158         * parameters is delegated to {@code DBMS_CLOUD_AI} and Oracle Database.</p>
159         *
160         * @return immutable {@link SyntheticDataBatchRequest}
161         * @throws IllegalArgumentException if no target object descriptors were added
162         */
163        public SyntheticDataBatchRequest build() {
164            if (objectList.isEmpty()) {
165                throw new IllegalArgumentException("At least one object must be provided in objectList");
166            }
167            return new SyntheticDataBatchRequest(this);
168        }
169    }
170}