import { MsSqlColumn, MsSqlColumnBuilder } from "./common.cjs";
import { entityKind } from "../../entity.cjs";
import { SQL, SQLGenerator } from "../../sql/sql.cjs";
import { Equal } from "../../utils.cjs";
import { ColumnBaseConfig } from "../../column.cjs";
import { MsSqlTable } from "../table.cjs";
import { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig } from "../../index.cjs";

//#region src/mssql-core/columns/custom.d.ts
type ConvertCustomConfig<T extends Partial<CustomTypeValues>> = {
  dataType: 'custom';
  data: T['data'];
  driverParam: T['driverData'];
} & (T['notNull'] extends true ? {
  notNull: true;
} : {}) & (T['default'] extends true ? {
  hasDefault: true;
} : {});
interface MsSqlCustomColumnInnerConfig {
  customTypeValues: CustomTypeValues;
}
declare class MsSqlCustomColumnBuilder<T extends ColumnBuilderBaseConfig<'custom'>> extends MsSqlColumnBuilder<T, {
  fieldConfig: CustomTypeValues['config'];
  customTypeParams: CustomTypeParams<any>;
}> {
  static readonly [entityKind]: string;
  constructor(name: string, fieldConfig: CustomTypeValues['config'], customTypeParams: CustomTypeParams<any>);
}
declare class MsSqlCustomColumn<T extends ColumnBaseConfig<'custom'>> extends MsSqlColumn<T> {
  static readonly [entityKind]: string;
  private sqlName;
  private mapTo?;
  private mapFrom?;
  private mapJson?;
  private forJsonSelect?;
  constructor(table: MsSqlTable<any>, config: ColumnBuilderRuntimeConfig<T['data']> & {
    fieldConfig: CustomTypeValues['config'];
    customTypeParams: CustomTypeParams<any>;
  });
  getSQLType(): string;
  mapFromDriverValue: (value: T["driverParam"]) => T["data"];
  mapFromJsonValue(value: unknown): T['data'];
  jsonSelectIdentifier(identifier: SQL, sql: SQLGenerator): SQL;
  mapToDriverValue: (value: T["data"]) => T["driverParam"];
}
type CustomTypeValues = {
  /**
   * Required type for custom column, that will infer proper type model
   *
   * Examples:
   *
   * If you want your column to be `string` type after selecting/or on inserting - use `data: string`. Like `text`, `varchar`
   *
   * If you want your column to be `number` type after selecting/or on inserting - use `data: number`. Like `integer`
   */
  data: unknown;
  /**
   * Type helper, that represents what type database driver is returning for specific database data type
   *
   * Needed only in case driver's output and input for type differ
   *
   * Defaults to {@link driverData}
   */
  driverOutput?: unknown;
  /**
   * Type helper, that represents what type database driver is accepting for specific database data type
   */
  driverData?: unknown;
  /**
   * Type helper, that represents what type field returns after being aggregated to JSON
   */
  jsonData?: unknown;
  /**
   * What config type should be used for {@link CustomTypeParams} `dataType` generation
   */
  config?: Record<string, any>;
  /**
   * Whether the config argument should be required or not
   * @default false
   */
  configRequired?: boolean;
  /**
   * If your custom data type should be notNull by default you can use `notNull: true`
   *
   * @example
   * const customSerial = customType<{ data: number, notNull: true, default: true }>({
   * 	  dataType() {
   * 	    return 'serial';
   *    },
   * });
   */
  notNull?: boolean;
  /**
   * If your custom data type has default you can use `default: true`
   *
   * @example
   * const customSerial = customType<{ data: number, notNull: true, default: true }>({
   * 	  dataType() {
   * 	    return 'serial';
   *    },
   * });
   */
  default?: boolean;
};
interface CustomTypeParams<T extends CustomTypeValues> {
  /**
   * Database data type string representation, that is used for migrations
   * @example
   * ```
   * `jsonb`, `text`
   * ```
   *
   * If database data type needs additional params you can use them from `config` param
   * @example
   * ```
   * `varchar(256)`, `numeric(2,3)`
   * ```
   *
   * To make `config` be of specific type please use config generic in {@link CustomTypeValues}
   *
   * @example
   * Usage example
   * ```
   *   dataType() {
   *     return 'boolean';
   *   },
   * ```
   * Or
   * ```
   *   dataType(config) {
   * 	   return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;
   * 	 }
   * ```
   */
  dataType: (config: T['config'] | (Equal<T['configRequired'], true> extends true ? never : undefined)) => string;
  /**
   * Optional mapping function, that is used to transform inputs from desired to be used in code format to one suitable for driver
   * @example
   * For example, when using jsonb we need to map JS/TS object to string before writing to database
   * ```
   * toDriver(value: TData): string {
   * 	 return JSON.stringify(value);
   * }
   * ```
   */
  toDriver?: (value: T['data']) => T['driverData'] | SQL;
  /**
   * Optional mapping function, that is used for transforming data returned by driver to desired column's output format
   * @example
   * For example, when using timestamp we need to map string Date representation to JS Date
   * ```
   * fromDriver(value: string): Date {
   * 	return new Date(value);
   * }
   * ```
   *
   * It'll cause the returned data to change from:
   * ```
   * {
   * 	customField: "2025-04-07 03:25:16.635";
   * }
   * ```
   * to:
   * ```
   * {
   * 	customField: new Date("2025-04-07 03:25:16.635");
   * }
   * ```
   */
  fromDriver?: (value: 'driverOutput' extends keyof T ? T['driverOutput'] : T['driverData']) => T['data'];
  /**
   * Optional mapping function, that is used for transforming data returned by transofmed to JSON in database data to desired format
   *
   * Used by [relational queries](https://orm.drizzle.team/docs/rqb-v2)
   *
   * Defaults to {@link fromDriver} function
   * @example
   * For example, when querying bigint column via [RQB](https://orm.drizzle.team/docs/rqb-v2) or [JSON functions](https://orm.drizzle.team/docs/json-functions), the result field will be returned as it's string representation, as opposed to bigint from regular query
   * To handle that, we need a separate function to handle such field's mapping:
   * ```
   * fromJson(value: string): bigint {
   * 	return BigInt(value);
   * },
   * ```
   *
   * It'll cause the returned data to change from:
   * ```
   * {
   * 	customField: "5044565289845416380";
   * }
   * ```
   * to:
   * ```
   * {
   * 	customField: 5044565289845416380n;
   * }
   * ```
   */
  fromJson?: (value: T['jsonData']) => T['data'];
  /**
   * Optional selection modifier function, that is used for modifying selection of column inside [JSON functions](https://orm.drizzle.team/docs/json-functions)
   *
   * Additional mapping that could be required for such scenarios can be handled using {@link fromJson} function
   *
   * Used by [relational queries](https://orm.drizzle.team/docs/rqb-v2)
   *
   * Following types are being casted to text by default: `binary`, `varbinary`, `time`, `datetime`, `decimal`, `float`, `bigint`
   * @example
   * For example, when using bigint we need to cast field to text to preserve data integrity
   * ```
   * forJsonSelect(identifier: SQL, sql: SQLGenerator): SQL {
   * 	return sql`cast(${identifier} as char)`
   * },
   * ```
   *
   * This will change query from:
   * ```
   * SELECT
   * 	json_build_object('bigint', `t`.`bigint`)
   * 	FROM
   * 	(
   * 		SELECT
   * 		`table`.`custom_bigint` AS `bigint`
   * 		FROM
   * 		`table`
   * 	) AS `t`
   * ```
   * to:
   * ```
   * SELECT
   * 	json_build_object('bigint', `t`.`bigint`)
   * 	FROM
   * 	(
   * 		SELECT
   * 		cast(`table`.`custom_bigint` as char) AS `bigint`
   * 		FROM
   * 		`table`
   * 	) AS `t`
   * ```
   *
   * Returned by query object will change from:
   * ```
   * {
   * 	bigint: 5044565289845416000; // Partial data loss due to direct conversion to JSON format
   * }
   * ```
   * to:
   * ```
   * {
   * 	bigint: "5044565289845416380"; // Data is preserved due to conversion of field to text before JSON-ification
   * }
   * ```
   */
  forJsonSelect?: (identifier: SQL, sql: SQLGenerator) => SQL;
}
/**
 * Custom mssql database data type generator
 */
declare function customType<T extends CustomTypeValues = CustomTypeValues>(customTypeParams: CustomTypeParams<T>): Equal<T['configRequired'], true> extends true ? {
  <TConfig extends Record<string, any> & T['config']>(fieldConfig: TConfig): MsSqlCustomColumnBuilder<ConvertCustomConfig<T>>;
  (dbName: string, fieldConfig: T['config']): MsSqlCustomColumnBuilder<ConvertCustomConfig<T>>;
} : {
  (): MsSqlCustomColumnBuilder<ConvertCustomConfig<T>>;
  <TConfig extends Record<string, any> & T['config']>(fieldConfig?: TConfig): MsSqlCustomColumnBuilder<ConvertCustomConfig<T>>;
  (dbName: string, fieldConfig?: T['config']): MsSqlCustomColumnBuilder<ConvertCustomConfig<T>>;
};
//#endregion
export { ConvertCustomConfig, CustomTypeParams, CustomTypeValues, MsSqlCustomColumn, MsSqlCustomColumnBuilder, MsSqlCustomColumnInnerConfig, customType };
//# sourceMappingURL=custom.d.cts.map