/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Other licenses:
 * -----------------------------------------------------------------------------
 * Commercial licenses for this work are available. These replace the above
 * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
 * database integrations.
 *
 * For more information, please visit: https://www.jooq.org/legal/licensing
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package org.jooq;

// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
// ...
import static org.jooq.SQLDialect.H2;
import static org.jooq.SQLDialect.HSQLDB;
// ...
import static org.jooq.SQLDialect.MARIADB;
// ...
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...

import java.sql.Connection;

import org.jetbrains.annotations.NotNull;

/**
 * The <code>Loader</code> API is used for configuring data loads.
 * <p>
 * Add options to for the loading behaviour. For performance reasons, you can
 * fine-tune three different types of measures:
 * <ul>
 * <li><strong>The bulk statement size</strong>. This specifies how many rows
 * will be inserted in a single bulk statement / multi-row <code>INSERT</code>
 * statement.</li>
 * <li><strong>The batch statement size</strong>. This specifies how many bulk
 * statements will be sent to the server as a single JDBC batch statement.</li>
 * <li><strong>The commit size</strong>. This specifies how many batch
 * statements will be committed in a single transaction.</li>
 * </ul>
 * <p>
 * <h3>Referencing <code>XYZ*Step</code> types directly from client code</h3>
 * <p>
 * It is usually not recommended to reference any <code>XYZ*Step</code> types
 * directly from client code, or assign them to local variables. When writing
 * dynamic SQL, creating a statement's components dynamically, and passing them
 * to the DSL API statically is usually a better choice. See the manual's
 * section about dynamic SQL for details: <a href=
 * "https://www.jooq.org/doc/latest/manual/sql-building/dynamic-sql">https://www.jooq.org/doc/latest/manual/sql-building/dynamic-sql</a>.
 * <p>
 * Drawbacks of referencing the <code>XYZ*Step</code> types directly:
 * <ul>
 * <li>They're operating on mutable implementations (as of jOOQ 3.x)</li>
 * <li>They're less composable and not easy to get right when dynamic SQL gets
 * complex</li>
 * <li>They're less readable</li>
 * <li>They might have binary incompatible changes between minor releases</li>
 * </ul>
 *
 * @author Lukas Eder
 */
public interface LoaderOptionsStep<R extends Record> extends LoaderSourceStep<R> {

    // -------------------------------------------------------------------------
    // Duplicate handling
    // -------------------------------------------------------------------------

    /**
     * Instruct the <code>Loader</code> to update duplicate records if any of
     * the unique keys' values are already in the database. This is only
     * supported if {@link InsertQuery#onDuplicateKeyUpdate(boolean)} is
     * supported, too.
     * <p>
     * If the loaded table does not have any unqiue keys, then all records are
     * inserted and this clause behaves like {@link #onDuplicateKeyIgnore()}
     * <p>
     * If you don't specify a behaviour, {@link #onDuplicateKeyError()} will be
     * the default. This cannot be combined with {@link #onDuplicateKeyError()}
     * or {@link #onDuplicateKeyIgnore()}
     */
    @NotNull @CheckReturnValue
    @Support({ CUBRID, DERBY, H2, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE })
    LoaderOptionsStep<R> onDuplicateKeyUpdate();

    /**
     * Instruct the <code>Loader</code> to skip duplicate records if any of the
     * unique keys' values are already in the database.
     * <p>
     * If the loaded table does not have any unique keys, then all records are
     * inserted. This may influence the JDBC driver's outcome on
     * {@link Connection#getWarnings()}, depending on your JDBC driver's
     * implementation
     * <p>
     * If you don't specify a behaviour, {@link #onDuplicateKeyError()} will be
     * the default. This cannot be combined with {@link #onDuplicateKeyError()}
     * or {@link #onDuplicateKeyUpdate()}
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> onDuplicateKeyIgnore();

    /**
     * Instruct the <code>Loader</code> to cause an error in loading if there
     * are any duplicate records.
     * <p>
     * If this is combined with {@link #onErrorAbort()} and {@link #commitAll()}
     * in a later step of <code>Loader</code>, then loading is rollbacked on
     * abort.
     * <p>
     * If you don't specify a behaviour, this will be the default. This cannot
     * be combined with {@link #onDuplicateKeyIgnore()} or
     * {@link #onDuplicateKeyUpdate()}
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> onDuplicateKeyError();

    // -------------------------------------------------------------------------
    // Error handling
    // -------------------------------------------------------------------------

    /**
     * Instruct the <code>Loader</code> to ignore any errors that might occur
     * when inserting a record. The <code>Loader</code> will then skip the
     * record and try inserting the next one. After loading, you can access
     * errors with {@link Loader#errors()}
     * <p>
     * If you don't specify a behaviour, {@link #onErrorAbort()} will be the
     * default. This cannot be combined with {@link #onErrorAbort()}
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> onErrorIgnore();

    /**
     * Instruct the <code>Loader</code> to abort loading after the first error
     * that might occur when inserting a record. After loading, you can access
     * errors with {@link Loader#errors()}
     * <p>
     * If this is combined with {@link #commitAll()} in a later step of
     * <code>Loader</code>, then loading is rollbacked on abort.
     * <p>
     * If you don't specify a behaviour, this will be the default. This cannot
     * be combined with {@link #onErrorIgnore()}
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> onErrorAbort();

    // -------------------------------------------------------------------------
    // Commit strategy
    // -------------------------------------------------------------------------

    /**
     * Commit each batch.
     * <p>
     * This is the same as calling {@link #commitAfter(int)} with <code>1</code>
     * as parameter.
     * <p>
     * With this clause, errors will never result in a rollback, even when you
     * specify {@link #onDuplicateKeyError()} or {@link #onErrorAbort()}
     * <p>
     * The COMMIT OPTIONS might be useful for fine-tuning performance behaviour
     * in some RDBMS, where large commits lead to a high level of concurrency in
     * the database. Use this on fresh transactions only. Commits/Rollbacks are
     * executed directly upon the connection returned by
     * {@link Configuration#connectionProvider()}. This might not work with
     * container-managed transactions, or when
     * {@link Connection#getAutoCommit()} is set to true.
     * <p>
     * If you don't specify a COMMIT OPTION, {@link #commitNone()} will be the
     * default, leaving transaction handling up to you.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> commitEach();

    /**
     * Commit after a certain number of batches.
     * <p>
     * With this clause, errors will never result in a rollback, even when you
     * specify {@link #onDuplicateKeyError()} or {@link #onErrorAbort()}
     * <p>
     * The COMMIT OPTIONS might be useful for fine-tuning performance behaviour
     * in some RDBMS, where large commits lead to a high level of concurrency in
     * the database. Use this on fresh transactions only. Commits/Rollbacks are
     * executed directly upon the connection returned by
     * {@link Configuration#connectionProvider()}. This might not work with
     * container-managed transactions, or when
     * {@link Connection#getAutoCommit()} is set to true.
     * <p>
     * If you don't specify a COMMIT OPTION, {@link #commitNone()} will be the
     * default, leaving transaction handling up to you.
     *
     * @param number The number of records that are committed together.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> commitAfter(int number);

    /**
     * Commit only after inserting all batches. If this is used together with
     * {@link #onDuplicateKeyError()} or {@link #onErrorAbort()}, an abort will
     * result in a rollback of previously loaded records.
     * <p>
     * The COMMIT OPTIONS might be useful for fine-tuning performance behaviour
     * in some RDBMS, where large commits lead to a high level of concurrency in
     * the database. Use this on fresh transactions only. Commits/Rollbacks are
     * executed directly upon the connection returned by
     * {@link Configuration#connectionProvider()}. This might not work with
     * container-managed transactions, or when
     * {@link Connection#getAutoCommit()} is set to true.
     * <p>
     * If you don't specify a COMMIT OPTION, {@link #commitNone()} will be the
     * default, leaving transaction handling up to you.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> commitAll();

    /**
     * Leave committing / rollbacking up to client code.
     * <p>
     * The COMMIT OPTIONS might be useful for fine-tuning performance behaviour
     * in some RDBMS, where large commits lead to a high level of concurrency in
     * the database.
     * <p>
     * If you don't specify a COMMIT OPTION, this will be the default, leaving
     * transaction handling up to you. This should be your choice, when you use
     * container-managed transactions, too, or your
     * {@link Connection#getAutoCommit()} value is set to true.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> commitNone();

    // -------------------------------------------------------------------------
    // Batch strategy
    // -------------------------------------------------------------------------

    /**
     * Batch all bulk statements in one JDBC batch statement.
     * <p>
     * If {@link #commitEach()} or {@link #commitAfter(int)} are set, this will
     * force the <code>COMMIT</code> option to {@link #commitAll()}.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> batchAll();

    /**
     * Do not batch bulk statements together.
     * <p>
     * If you don't specify a BATCH OPTION, this will be the default.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> batchNone();

    /**
     * Batch a given number of bulk statements together.
     *
     * @param number The number of records that are batched together.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> batchAfter(int number);

    // -------------------------------------------------------------------------
    // Bulk strategy
    // -------------------------------------------------------------------------

    /**
     * Bulk-insert all rows in a single multi-row bulk statement.
     * <p>
     * If {@link #commitEach()} or {@link #commitAfter(int)} are set, this will
     * force the <code>COMMIT</code> option to {@link #commitAll()}.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> bulkAll();

    /**
     * Do not bulk-insert rows in multi-row bulk statements.
     * <p>
     * If you don't specify a BULK OPTION, this will be the default.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> bulkNone();

    /**
     * Bulk-insert a given number of statements in a single multi-row bulk
     * statement.
     * <p>
     * If {@link #commitEach()} is set, each bulk statement will be committed.
     * If {@link #commitAfter(int)} is set, the given number of bulk statements
     * are committed.
     *
     * @param number The number of records that are put together in one bulk
     *            statement.
     */
    @NotNull @CheckReturnValue
    @Support
    LoaderOptionsStep<R> bulkAfter(int number);
}
