import { BetterAuthDBSchema, DBFieldAttribute } from "../type.mjs";
import { initGetDefaultFieldName } from "./get-default-field-name.mjs";
import { initGetDefaultModelName } from "./get-default-model-name.mjs";
import { initGetFieldAttributes } from "./get-field-attributes.mjs";
import { initGetFieldName } from "./get-field-name.mjs";
import { initGetIdField } from "./get-id-field.mjs";
import { initGetModelName } from "./get-model-name.mjs";
import { AdapterConfig, AdapterFactoryConfig, AdapterFactoryCustomizeAdapterCreator, AdapterFactoryOptions, AdapterTestDebugLogs, CreateAdapterOptions, CreateCustomAdapter } from "./types.mjs";
import { AdapterFactory, createAdapter, createAdapterFactory } from "./factory.mjs";
import { deepmerge, withApplyDefault } from "./utils.mjs";
import { BetterAuthOptions } from "../../types/init-options.mjs";
import "../../types/index.mjs";

//#region src/db/adapter/index.d.ts
type DBAdapterDebugLogOption = boolean | {
  /**
   * Useful when you want to log only certain conditions.
   */
  logCondition?: (() => boolean) | undefined;
  create?: boolean | undefined;
  update?: boolean | undefined;
  updateMany?: boolean | undefined;
  findOne?: boolean | undefined;
  findMany?: boolean | undefined;
  delete?: boolean | undefined;
  deleteMany?: boolean | undefined;
  count?: boolean | undefined;
} | {
  /**
   * Only used for adapter tests to show debug logs if a test fails.
   *
   * @deprecated Not actually deprecated. Doing this for IDEs to show this option at the very bottom and stop end-users from using this.
   */
  isRunningAdapterTests: boolean;
};
type DBAdapterSchemaCreation = {
  /**
   * Code to be inserted into the file
   */
  code: string;
  /**
   * Path to the file, including the file name and extension.
   * Relative paths are supported, with the current working directory of the developer's project as the base.
   */
  path: string;
  /**
   * Append the file if it already exists.
   * Note: This will not apply if `overwrite` is set to true.
   */
  append?: boolean | undefined;
  /**
   * Overwrite the file if it already exists
   */
  overwrite?: boolean | undefined;
};
interface DBAdapterFactoryConfig<Options extends BetterAuthOptions = BetterAuthOptions> {
  /**
   * Use plural table names.
   *
   * All tables will be named with an `s` at the end.
   *
   * @default false
   */
  usePlural?: boolean | undefined;
  /**
   * Enable debug logs.
   *
   * @default false
   */
  debugLogs?: DBAdapterDebugLogOption | undefined;
  /**
   * Name of the adapter.
   *
   * This is used to identify the adapter in the debug logs.
   *
   * @default `adapterId`
   */
  adapterName?: string | undefined;
  /**
   * Adapter id
   */
  adapterId: string;
  /**
   * If the database supports numeric ids, set this to `true`.
   *
   * @default true
   */
  supportsNumericIds?: boolean | undefined;
  /**
   * If the database supports natively generating UUIDs, set this to `true`.
   *
   * @default false
   */
  supportsUUIDs?: boolean | undefined;
  /**
   * If the database doesn't support JSON columns, set this to `false`.
   *
   * We will handle the translation between using `JSON` columns, and saving `string`s to the database.
   *
   * @default false
   */
  supportsJSON?: boolean | undefined;
  /**
   * If the database doesn't support dates, set this to `false`.
   *
   * We will handle the translation between using `Date` objects, and saving `string`s to the database.
   *
   * @default true
   */
  supportsDates?: boolean | undefined;
  /**
   * If the database doesn't support booleans, set this to `false`.
   *
   * We will handle the translation between using `boolean`s, and saving `0`s and `1`s to the database.
   *
   * @default true
   */
  supportsBooleans?: boolean | undefined;
  /**
   * If the database doesn't support arrays, set this to `false`.
   *
   * We will handle the translation between using `array`s, and saving `string`s to the database.
   *
   * @default false
   */
  supportsArrays?: boolean | undefined;
  /**
   * Execute multiple operations in a transaction.
   *
   * If the database doesn't support transactions, set this to `false` and operations will be executed sequentially.
   *
   * @default false
   */
  transaction?: (false | (<R>(callback: (trx: DBTransactionAdapter<Options>) => Promise<R>) => Promise<R>)) | undefined;
  /**
   * Disable id generation for the `create` method.
   *
   * This is useful for databases that don't support custom id values and would auto-generate them for you.
   *
   * @default false
   */
  disableIdGeneration?: boolean | undefined;
  /**
   * Map the keys of the input data.
   *
   * This is useful for databases that expect a different key name for a given situation.
   *
   * For example, MongoDB uses `_id` while in Better-Auth we use `id`.
   *
   *
   * @example
   * Each key represents the old key to replace.
   * The value represents the new key
   *
   * This can be a partial object that only transforms some keys.
   *
   * ```ts
   * mapKeysTransformInput: {
   *  id: "_id" // We want to replace `id` to `_id` to save into MongoDB
   * }
   * ```
   */
  mapKeysTransformInput?: Record<string, string> | undefined;
  /**
   * Map the keys of the output data.
   *
   * This is useful for databases that expect a different key name for a given situation.
   *
   * For example, MongoDB uses `_id` while in Better-Auth we use `id`.
   *
   * @example
   * Each key represents the old key to replace.
   * The value represents the new key
   *
   * This can be a partial object that only transforms some keys.
   *
   * ```ts
   * mapKeysTransformOutput: {
   *  _id: "id" // In MongoDB, we save `id` as `_id`. So we want to replace `_id` with `id` when we get the data back.
   * }
   * ```
   */
  mapKeysTransformOutput?: Record<string, string> | undefined;
  /**
   * Custom transform input function.
   *
   * This function is used to transform the input data before it is saved to the database.
   */
  customTransformInput?: ((props: {
    data: any;
    /**
     * The fields of the model.
     */
    fieldAttributes: DBFieldAttribute;
    /**
     * The field to transform.
     */
    field: string;
    /**
     * The action which was called from the adapter.
     */
    action: "create" | "update" | "findOne" | "findMany" | "updateMany" | "delete" | "deleteMany" | "count";
    /**
     * The model name.
     */
    model: string;
    /**
     * The schema of the user's Better-Auth instance.
     */
    schema: BetterAuthDBSchema;
    /**
     * The options of the user's Better-Auth instance.
     */
    options: Options;
  }) => any) | undefined;
  /**
   * Custom transform output function.
   *
   * This function is used to transform the output data before it is returned to the user.
   */
  customTransformOutput?: ((props: {
    data: any;
    /**
     * The fields of the model.
     */
    fieldAttributes: DBFieldAttribute;
    /**
     * The field to transform.
     */
    field: string;
    /**
     * The fields to select.
     */
    select: string[];
    /**
     * The model name.
     */
    model: string;
    /**
     * The schema of the user's Better-Auth instance.
     */
    schema: BetterAuthDBSchema;
    /**
     * The options of the user's Better-Auth instance.
     */
    options: Options;
  }) => any) | undefined;
  /**
   * Custom ID generator function.
   *
   * By default, we can handle ID generation for you, however if the database your adapter is for only supports a specific custom id generation,
   * then you can use this function to generate your own IDs.
   *
   *
   * Notes:
   * - If the user enabled `useNumberId` or `generateId` set to `serial`, then this option will be ignored. Unless this adapter config has `supportsNumericIds` set to `false`.
   * - If `generateId` is `false` in the user's Better-Auth config, then this option will be ignored.
   * - If `generateId` is a function, then it will override this option.
   *
   * @example
   *
   * ```ts
   * customIdGenerator: ({ model }) => {
   *  return "my-super-unique-id";
   * }
   * ```
   */
  customIdGenerator?: ((props: {
    model: string;
  }) => string) | undefined;
  /**
   * Whether to disable the transform output.
   * Do not use this option unless you know what you are doing.
   * @default false
   */
  disableTransformOutput?: boolean | undefined;
  /**
   * Whether to disable the transform input.
   * Do not use this option unless you know what you are doing.
   * @default false
   */
  disableTransformInput?: boolean | undefined;
  /**
   * Whether to disable the transform join.
   * Do not use this option unless you know what you are doing.
   * @default false
   */
  disableTransformJoin?: boolean | undefined;
}
type Where = {
  /**
   * @default eq
   */
  operator?: ("eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with") | undefined;
  value: string | number | boolean | string[] | number[] | Date | null;
  field: string;
  /**
   * @default AND
   */
  connector?: ("AND" | "OR") | undefined;
};
/**
 * JoinOption configuration for relational queries.
 *
 * Allows you to join related tables/models in a single query operation.
 * Each key represents the name of the joined table/model, and the value
 * configures how the join should be performed.
 */
type JoinOption = {
  [model: string]: boolean | {
    limit?: number;
  };
};
/**
 * Once `JoinOption` has gone through the adapter factory, it will be transformed into a `JoinConfig`.
 */
type JoinConfig = {
  [model: string]: {
    /**
     * The joining column names.
     */
    on: {
      /**
       * Column name from the main table
       */
      from: string;
      /**
       * Column name from the joined table
       */
      to: string;
    };
    /**
     * Limit the number of rows to return.
     *
     * If the relation has `unique` constraint, then this option will be ignored and limit will be set to 1.
     *
     * @default 100
     */
    limit?: number;
    /**
     * The relation type. Determines the output joined model data.
     *
     * `one-to-one` would have a single object in the output.
     * `one-to-many` would have an array of objects in the output.
     * `many-to-many` would have an array of objects in the output.
     *
     * @default "one-to-many"
     */
    relation?: "one-to-one" | "one-to-many" | "many-to-many";
  };
};
type DBTransactionAdapter<Options extends BetterAuthOptions = BetterAuthOptions> = Omit<DBAdapter<Options>, "transaction">;
type DBAdapter<Options extends BetterAuthOptions = BetterAuthOptions> = {
  id: string;
  create: <T extends Record<string, any>, R = T>(data: {
    model: string;
    data: Omit<T, "id">;
    select?: string[] | undefined;
    /**
     * By default, any `id` provided in `data` will be ignored.
     *
     * If you want to force the `id` to be the same as the `data.id`, set this to `true`.
     */
    forceAllowId?: boolean | undefined;
  }) => Promise<R>;
  findOne: <T>(data: {
    model: string;
    where: Where[];
    select?: string[] | undefined;
    join?: JoinOption | undefined;
  }) => Promise<T | null>;
  findMany: <T>(data: {
    model: string;
    where?: Where[] | undefined;
    limit?: number | undefined;
    select?: string[] | undefined;
    sortBy?: {
      field: string;
      direction: "asc" | "desc";
    } | undefined;
    offset?: number | undefined;
    join?: JoinOption | undefined;
  }) => Promise<T[]>;
  count: (data: {
    model: string;
    where?: Where[] | undefined;
  }) => Promise<number>;
  /**
   * ⚠︎ Update may not return the updated data
   * if multiple where clauses are provided
   */
  update: <T>(data: {
    model: string;
    where: Where[];
    update: Record<string, any>;
  }) => Promise<T | null>;
  updateMany: (data: {
    model: string;
    where: Where[];
    update: Record<string, any>;
  }) => Promise<number>;
  delete: <_T>(data: {
    model: string;
    where: Where[];
  }) => Promise<void>;
  deleteMany: (data: {
    model: string;
    where: Where[];
  }) => Promise<number>;
  /**
   * Execute multiple operations in a transaction.
   * If the adapter doesn't support transactions, operations will be executed sequentially.
   */
  transaction: <R>(callback: (trx: DBTransactionAdapter<Options>) => Promise<R>) => Promise<R>;
  /**
   *
   * @param options
   * @param file - file path if provided by the user
   */
  createSchema?: ((options: Options, file?: string) => Promise<DBAdapterSchemaCreation>) | undefined;
  options?: ({
    adapterConfig: DBAdapterFactoryConfig<Options>;
  } & CustomAdapter["options"]) | undefined;
};
type CleanedWhere = Required<Where>;
interface CustomAdapter {
  create: <T extends Record<string, any>>({
    data,
    model,
    select
  }: {
    model: string;
    data: T;
    select?: string[] | undefined;
  }) => Promise<T>;
  update: <T>(data: {
    model: string;
    where: CleanedWhere[];
    update: T;
  }) => Promise<T | null>;
  updateMany: (data: {
    model: string;
    where: CleanedWhere[];
    update: Record<string, any>;
  }) => Promise<number>;
  findOne: <T>({
    model,
    where,
    select,
    join
  }: {
    model: string;
    where: CleanedWhere[];
    select?: string[] | undefined;
    join?: JoinConfig | undefined;
  }) => Promise<T | null>;
  findMany: <T>({
    model,
    where,
    limit,
    select,
    sortBy,
    offset,
    join
  }: {
    model: string;
    where?: CleanedWhere[] | undefined;
    limit: number;
    select?: string[] | undefined;
    sortBy?: {
      field: string;
      direction: "asc" | "desc";
    } | undefined;
    offset?: number | undefined;
    join?: JoinConfig | undefined;
  }) => Promise<T[]>;
  delete: ({
    model,
    where
  }: {
    model: string;
    where: CleanedWhere[];
  }) => Promise<void>;
  deleteMany: ({
    model,
    where
  }: {
    model: string;
    where: CleanedWhere[];
  }) => Promise<number>;
  count: ({
    model,
    where
  }: {
    model: string;
    where?: CleanedWhere[] | undefined;
  }) => Promise<number>;
  createSchema?: ((props: {
    /**
     * The file the user may have passed in to the `generate` command as the expected schema file output path.
     */
    file?: string;
    /**
     * The tables from the user's Better-Auth instance schema.
     */
    tables: BetterAuthDBSchema;
  }) => Promise<DBAdapterSchemaCreation>) | undefined;
  /**
   * Your adapter's options.
   */
  options?: Record<string, any> | undefined;
}
interface DBAdapterInstance<Options extends BetterAuthOptions = BetterAuthOptions> {
  (options: BetterAuthOptions): DBAdapter<Options>;
}
//#endregion
export { AdapterConfig, AdapterFactory, AdapterFactoryConfig, AdapterFactoryCustomizeAdapterCreator, AdapterFactoryOptions, AdapterTestDebugLogs, CleanedWhere, CreateAdapterOptions, CreateCustomAdapter, CustomAdapter, DBAdapter, DBAdapterDebugLogOption, DBAdapterFactoryConfig, DBAdapterInstance, DBAdapterSchemaCreation, DBTransactionAdapter, JoinConfig, JoinOption, Where, createAdapter, createAdapterFactory, deepmerge, initGetDefaultFieldName, initGetDefaultModelName, initGetFieldAttributes, initGetFieldName, initGetIdField, initGetModelName, withApplyDefault };
//# sourceMappingURL=index.d.mts.map