var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });

// src/models/fields/field.ts
import { utils } from "@palmares/core";

// src/models/fields/utils.ts
async function defaultToStringCallback(engine, field, _, customParams = void 0) {
  let customImports = [];
  let stringifiedCustomAttributes = "{}";
  if (engine.fields.fieldToString) {
    const stringifiedField = engine.fields.fieldToString(field["__customAttributes"]);
    customImports = stringifiedField.imports;
    stringifiedCustomAttributes = stringifiedField.result;
  }
  const stringfieldDefaultValue = field["__defaultValue"] === void 0 ? void 0 : JSON.stringify(field["__defaultValue"]);
  return {
    stringfied: `models.fields.${field["__typeName"]}.new(${customParams?.constructorParams ? `${customParams.constructorParams}` : ""})${typeof field["__primaryKey"] === "boolean" ? `.primaryKey(${field["__primaryKey"]})` : ""}${stringfieldDefaultValue !== void 0 ? `.default(${typeof field["__defaultValue"] === "string" ? `"${stringfieldDefaultValue}"` : stringfieldDefaultValue})` : ""}${typeof field["__allowNull"] === "boolean" ? `.allowNull(${field["__allowNull"]})` : ""}${typeof field["__unique"] === "boolean" ? `.unique(${field["__unique"]})` : ""}${typeof field["__dbIndex"] === "boolean" ? `.dbIndex(${field["__dbIndex"]})` : ""}${typeof field["__databaseName"] === "string" ? `.databaseName("${field["__databaseName"]}")` : ""}${typeof field["__underscored"] === "boolean" ? `.underscored(${field["__underscored"]})` : ""}${typeof stringifiedCustomAttributes === "string" ? `.setCustomAttributes(${stringifiedCustomAttributes})` : ""}${customParams?.builderParams ? `${customParams.builderParams}` : ""}`,
    customImports
  };
}
__name(defaultToStringCallback, "defaultToStringCallback");
function defaultCompareCallback(engine, existingField, newField, _) {
  let isCustomAttributesEqual = true;
  if (engine.fields.compare) {
    const areCustomAttributesEqual = engine.fields.compare(existingField["__customAttributes"], newField["__customAttributes"]);
    isCustomAttributesEqual = areCustomAttributesEqual;
  }
  const isTypeNameEqual = existingField["__typeName"] === newField["__typeName"];
  const isAllowNullEqual = existingField["__allowNull"] === newField["__allowNull"];
  const isPrimaryKeyEqual = existingField["__primaryKey"] === newField["__primaryKey"];
  const isDefaultValueEqual = existingField["__defaultValue"] === newField["__defaultValue"];
  const isUniqueEqual = existingField["__unique"] === newField["__unique"];
  const isDbIndexEqual = existingField["__dbIndex"] === newField["__dbIndex"];
  const isDatabaseNameEqual = existingField["__databaseName"] === newField["__databaseName"];
  const isUnderscoredEqual = existingField["__underscored"] === newField["__underscored"];
  const changedAttributes = [
    !isTypeNameEqual && "typeName",
    !isAllowNullEqual && "allowNull",
    !isCustomAttributesEqual && "customAttributes",
    !isPrimaryKeyEqual && "primaryKey",
    !isDefaultValueEqual && "defaultValue",
    !isUniqueEqual && "unique",
    !isDbIndexEqual && "dbIndex",
    !isDatabaseNameEqual && "databaseName",
    !isUnderscoredEqual && "underscored"
  ].filter((attr) => typeof attr === "string");
  return [
    changedAttributes.length === 0,
    changedAttributes
  ];
}
__name(defaultCompareCallback, "defaultCompareCallback");
function defaultOptionsCallback(setFieldValue, oldField, _) {
  setFieldValue("__allowNull", "allowNull", oldField["__allowNull"]);
  setFieldValue("__customAttributes", "customAttributes", oldField["__customAttributes"]);
  setFieldValue("__defaultValue", "defaultValue", oldField["__defaultValue"]);
  setFieldValue("__dbIndex", "dbIndex", oldField["__dbIndex"]);
  setFieldValue("__databaseName", "databaseName", oldField["__databaseName"]);
  setFieldValue("__primaryKey", "primaryKey", oldField["__primaryKey"]);
  setFieldValue("__underscored", "underscored", oldField["__underscored"]);
  setFieldValue("__unique", "unique", oldField["__unique"]);
  setFieldValue("__isAuto", "isAuto", oldField["__isAuto"]);
  setFieldValue("__fieldName", "fieldName", oldField["__fieldName"]);
  setFieldValue("__model", void 0, oldField["__model"]);
}
__name(defaultOptionsCallback, "defaultOptionsCallback");
function defaultNewInstanceArgumentsCallback(_field, _defaultNewInstanceArgumentsCallback) {
  return [];
}
__name(defaultNewInstanceArgumentsCallback, "defaultNewInstanceArgumentsCallback");
function defaultGetArgumentsCallback(field, _) {
  return {
    $field: field,
    $model: field["__model"],
    typeName: field["__typeName"],
    fieldName: field["__fieldName"],
    modelName: field["__model"]?.["__getName"]?.() || "",
    isAuto: field["__isAuto"],
    primaryKey: field["__primaryKey"],
    defaultValue: field["__defaultValue"],
    allowNull: field["__allowNull"],
    unique: field["__unique"],
    dbIndex: field["__dbIndex"],
    databaseName: field["__databaseName"],
    underscored: field["__underscored"],
    customAttributes: field["__customAttributes"]
  };
}
__name(defaultGetArgumentsCallback, "defaultGetArgumentsCallback");

// src/models/fields/field.ts
var Field = class {
  static {
    __name(this, "Field");
  }
  $$type = "$PField";
  __typeName = "Field";
  __isAuto = false;
  __hasDefaultValue = false;
  __primaryKey = false;
  __defaultValue = void 0;
  __allowNull = false;
  __unique = false;
  __dbIndex = false;
  __databaseName = void 0;
  __underscored = true;
  __customAttributes;
  __allowedQueryOperations = /* @__PURE__ */ new Set([
    "eq",
    "is",
    "greaterThan",
    "lessThan",
    "like",
    "between",
    "and",
    "or"
  ]);
  // eslint-disable-next-line ts/require-await
  __toStringCallback = defaultToStringCallback;
  // eslint-disable-next-line ts/require-await
  __compareCallback = defaultCompareCallback;
  __optionsCallback = defaultOptionsCallback;
  __newInstanceCallback = defaultNewInstanceArgumentsCallback;
  __customImports = [];
  __getArgumentsCallback = defaultGetArgumentsCallback;
  __inputParsers = /* @__PURE__ */ new Map();
  __outputParsers = /* @__PURE__ */ new Map();
  __model;
  __fieldName;
  constructor(..._args) {
  }
  /**
  * Supposed to be used by library maintainers.
  *
  * When you custom create a field, you might want to take advantage of the builder pattern we already support.
  * This let's you create functions that can be chained together to create a new field. It should be used
  * alongside the `_setPartialAttributes` method like
  *
  * @example
  * ```ts
  * const customBigInt = TextField.overrideType<
  *   { create: bigint; read: bigint; update: bigint },
  *   {
  *       customAttributes: { name: string };
  *       unique: boolean;
  *       auto: boolean;
  *       allowNull: true;
  *       dbIndex: boolean;
  *       isPrimaryKey: boolean;
  *       defaultValue: any;
  *       typeName: string;
  *       engineInstance: DatabaseAdapter;
  *   }
  * >({
  *   typeName: 'CustomBigInt'
  * });
  *
  * const customBuilder = <TParams extends { name: string }>(params: TParams) => {
  *   const field = customBigInt.new(params);
  *   return field._setNewBuilderMethods({
  *     test: <TTest extends { age: number }>(param: TTest) =>
  *        // This will union the type `string` with what already exists in the field 'create' type
  *        field._setPartialAttributes<{ create: string }, { create: 'union' }>(param)
  *   });
  * };
  *
  * // Then your user can use it like:
  *
  * const field = customBuilder({ name: 'test' }).test({ age: 2 });
  * ```
  *
  * **Important**: `customBuilder` will be used by the end user and you are responsible for documenting it.
  */
  _setNewBuilderMethods(functions) {
    if (functions === void 0) return this;
    const propertiesOfBase = Object.getOwnPropertyNames(Object.getPrototypeOf(functions));
    for (const key of propertiesOfBase) {
      if (key === "constructor") continue;
      this[key] = functions[key].bind(this);
    }
    return this;
  }
  /**
  * FOR LIBRARY MAINTAINERS ONLY
  *
  * Focused for library maintainers that want to support a custom field type not supported by palmares.
  * This let's them partially update the custom attributes of the field. By default setCustomAttributes
  * will override the custom attributes entirely.
  */
  _setPartialAttributes() {
    return (partialCustomAttributes) => {
      if (partialCustomAttributes !== void 0) {
        if (this.__customAttributes === void 0) this.__customAttributes = {};
        this.__customAttributes = {
          ...this.__customAttributes,
          ...partialCustomAttributes
        };
      }
      return this;
    };
  }
  setCustomAttributes(customAttributes) {
    this.__customAttributes = customAttributes;
    return this;
  }
  unique(isUnique) {
    if (typeof isUnique !== "boolean") isUnique = true;
    this.__unique = isUnique;
    return this;
  }
  allowNull(isNull) {
    if (typeof isNull !== "boolean") isNull = true;
    this.__allowNull = isNull;
    return this;
  }
  /**
  * This method is used to create an index on the database for this field.
  */
  dbIndex(dbIndex) {
    if (typeof dbIndex !== "boolean") dbIndex = true;
    this.__dbIndex = dbIndex;
    return this;
  }
  underscored(isUnderscored) {
    if (typeof isUnderscored !== "boolean") isUnderscored = true;
    this.__underscored = isUnderscored;
    return this;
  }
  primaryKey(isPrimaryKey) {
    if (typeof isPrimaryKey !== "boolean") isPrimaryKey = true;
    this.__primaryKey = isPrimaryKey;
    return this;
  }
  auto(isAuto) {
    if (typeof isAuto !== "boolean") isAuto = true;
    this.__isAuto = isAuto;
    return this;
  }
  default(defaultValue) {
    this.__defaultValue = defaultValue;
    return this;
  }
  databaseName(databaseName) {
    this.__databaseName = databaseName;
    return this;
  }
  /**
  * This method can be used to override the type of a field. This is useful for library
  * maintainers that want to support the field type but the default type provided by palmares
  * is not the one that the user want to use.
  *
  * @example
  * ```ts
  * const MyCustomDatabaseAutoField = AutoField.overrideType<{ input: string; output: string }>();
  *
  * // then the user can use as normal:
  *
  * const autoField = MyCustomDatabaseAutoField.new();
  *
  * // now the type inferred for the field will be a string instead of a number.
  * ```
  *
  * ### Note
  *
  * Your library should provide documentation of the fields that are supported.
  */
  static _overrideType(args) {
    this.new = (params) => {
      const newInstance = new this(params);
      newInstance.__customImports = args.customImports || [];
      newInstance.__toStringCallback = args.toStringCallback || defaultToStringCallback;
      newInstance.__compareCallback = args.compareCallback || defaultCompareCallback;
      newInstance.__optionsCallback = args.optionsCallback || defaultOptionsCallback;
      newInstance.__newInstanceCallback = args.newInstanceCallback || defaultNewInstanceArgumentsCallback;
      newInstance.__typeName = args.typeName;
      newInstance.__allowedQueryOperations = /* @__PURE__ */ new Set([
        "is",
        "eq",
        "greaterThan",
        "lessThan",
        "like",
        "between"
      ]);
      newInstance["__customAttributes"] = params;
      return newInstance;
    };
    return this;
  }
  /**
  * This method enables the framework to automatically import the files when generating the migrations.
  *
  * This is generally useful for custom field types.
  *
  * @return - Returns a list of packages that we want to import in the migration file.
  */
  // eslint-disable-next-line ts/require-await
  async __getCustomImports() {
    return this["__customImports"];
  }
  __init(fieldName, model) {
    const isAlreadyInitialized = this.__model !== void 0 && typeof this.__fieldName === "string";
    if (isAlreadyInitialized) return;
    const isUnderscored = (this.__underscored || model.__cachedOptions?.underscored) === true;
    this.__fieldName = fieldName;
    this.__model = model;
    if (this.__primaryKey) model["__primaryKeys"].push(this.__fieldName);
    if (isUnderscored) this.__databaseName = utils.camelCaseToHyphenOrSnakeCase(this.__fieldName);
    else this.__databaseName = this.__fieldName;
  }
  /**
  * Gets all of the arguments to pass to the field during migration, translation, etc.
  *
  * Everything in the field is protected, this way end users don't access the internal implementation.
  */
  __getArguments() {
    return this.__getArgumentsCallback(this, defaultGetArgumentsCallback);
  }
  // eslint-disable-next-line ts/require-await
  async __toString(engine) {
    return this.__toStringCallback(engine, this, defaultToStringCallback, void 0);
  }
  /**
  * Used for comparing one field with the other so we are able to tell if they are different or not.
  *
  * This is obligatory to add if you create any custom fields.
  *
  * For custom fields you will call this super method before continuing, we first check if they are the same type.
  *
  * @param field - The field to compare to.
  *
  * @return - Returns true if the fields are equal and false otherwise
  */
  // eslint-disable-next-line ts/require-await
  __compare(engine, field) {
    return this.__compareCallback(engine, this, field, defaultCompareCallback);
  }
  /**
  * Used for cloning the field to a new field.
  *
  * @param oldField - The field to clone. If not provided it will use the current field.
  *
  * @returns - Returns the cloned field.
  */
  __clone(oldField, args) {
    const argumentsToPass = oldField.__newInstanceCallback(oldField, defaultNewInstanceArgumentsCallback);
    const overridenArguments = args?.newInstanceOverrideCallback?.(argumentsToPass) || argumentsToPass;
    const newInstanceOfField = oldField.constructor.new(...Array.isArray(overridenArguments) ? overridenArguments : []);
    oldField.__optionsCallback((hiddenAttributeName, getAttributesAttributeName, value) => {
      let actualValueToSet = value;
      if (getAttributesAttributeName && args?.optionsOverrideCallback?.[getAttributesAttributeName] !== void 0) actualValueToSet = (args?.optionsOverrideCallback)[getAttributesAttributeName](value);
      newInstanceOfField[hiddenAttributeName] = actualValueToSet;
    }, oldField, defaultOptionsCallback);
    return newInstanceOfField;
  }
  /**
  * You should not use this method directly, it is used internally by the framework.
  *
  * This method is used to create a new instance of the field with the same options as the old field.
  */
  static new(..._args) {
    return new this(..._args);
  }
};

// src/models/fields/text.ts
function text() {
  return TextField.new();
}
__name(text, "text");
var TextField = class extends Field {
  static {
    __name(this, "TextField");
  }
  $$type = "$PTextField";
  __typeName = "TextField";
  __allowedQueryOperations = /* @__PURE__ */ new Set([
    "and",
    "in",
    "or",
    "eq",
    "is",
    "like"
  ]);
  __allowBlank = false;
  __inputParsers = /* @__PURE__ */ new Map();
  __outputParsers = /* @__PURE__ */ new Map();
  __compareCallback = /* @__PURE__ */ __name((engine, oldField, newField, defaultCompareCallback2) => {
    const oldFieldAsTextField = oldField;
    const newFieldAsTextField = newField;
    const isAllowBlankEqual = oldFieldAsTextField["__allowBlank"] === newFieldAsTextField["__allowBlank"];
    const [isEqual, changedAttributes] = defaultCompareCallback2(engine, oldField, newField, defaultCompareCallback2);
    if (!isAllowBlankEqual) changedAttributes.push("allowBlank");
    return [
      isAllowBlankEqual && isEqual,
      changedAttributes
    ];
  }, "__compareCallback");
  __optionsCallback = /* @__PURE__ */ __name((setFieldValue, oldField, defaultOptionsCallback2) => {
    const oldFieldAsTextField = oldField;
    defaultOptionsCallback2(setFieldValue, oldField, defaultOptionsCallback2);
    setFieldValue("__allowBlank", "allowBlank", oldFieldAsTextField["__allowBlank"]);
  }, "__optionsCallback");
  __getArgumentsCallback = /* @__PURE__ */ __name((field, defaultGetArgumentsCallback2) => {
    const fieldAsTextField = field;
    const defaultData = defaultGetArgumentsCallback2(field, defaultGetArgumentsCallback2);
    return {
      ...defaultData,
      allowBlank: fieldAsTextField["__allowBlank"]
    };
  }, "__getArgumentsCallback");
  /**
  * This is used internally by the engine to convert the field to string.
  * You can override this if you want to extend the ForeignKeyField class.
  */
  __toStringCallback = /* @__PURE__ */ __name(async (engine, field, defaultToStringCallback2, _customParams = void 0) => {
    const fieldAsTextField = field;
    return await defaultToStringCallback2(engine, field, defaultToStringCallback2, {
      builderParams: `${typeof fieldAsTextField["__allowBlank"] === "boolean" ? `.allowBlank(${fieldAsTextField["__allowBlank"]})` : ""}`
    });
  }, "__toStringCallback");
  /**
  * Supposed to be used by library maintainers.
  *
  * When you custom create a field, you might want to take advantage of the builder pattern we already support.
  * This let's you create functions that can be chained together to create a new field. It should be used
  * alongside the `_setPartialAttributes` method like
  *
  * @example
  * ```ts
  * const customBigInt = TextField.overrideType<
  *   { create: bigint; read: bigint; update: bigint },
  *   {
  *       customAttributes: { name: string };
  *       unique: boolean;
  *       auto: boolean;
  *       allowNull: true;
  *       dbIndex: boolean;
  *       isPrimaryKey: boolean;
  *       defaultValue: any;
  *       typeName: string;
  *       engineInstance: DatabaseAdapter;
  *   }
  * >({
  *   typeName: 'CustomBigInt'
  * });
  *
  * const customBuilder = <TParams extends { name: string }>(params: TParams) => {
  *   const field = customBigInt.new(params);
  *   return field._setNewBuilderMethods({
  *     test: <TTest extends { age: number }>(param: TTest) =>
  *        // This will union the type `string` with what already exists in the field 'create' type
  *        field._setPartialAttributes<{ create: string }, { create: 'union' }>(param)
  *   });
  * };
  *
  * // Then your user can use it like:
  *
  * const field = customBuilder({ name: 'test' }).test({ age: 2 });
  * ```
  *
  * **Important**: `customBuilder` will be used by the end user and you are responsible for documenting it.
  */
  _setNewBuilderMethods(functions) {
    if (functions === void 0) return this;
    const propertiesOfBase = Object.getOwnPropertyNames(Object.getPrototypeOf(functions));
    for (const key of propertiesOfBase) {
      if (key === "constructor") continue;
      this[key] = functions[key].bind(this);
    }
    return this;
  }
  /**
  * FOR LIBRARY MAINTAINERS ONLY
  *
  * Focused for library maintainers that want to support a custom field type not supported by palmares.
  * This let's them partially update the custom attributes of the field. By default setCustomAttributes
  * will override the custom attributes entirely.
  */
  _setPartialAttributes() {
    return (partialCustomAttributes) => {
      if (partialCustomAttributes !== void 0) {
        if (this.__customAttributes === void 0) this.__customAttributes = {};
        this.__customAttributes = {
          ...this.__customAttributes,
          ...partialCustomAttributes
        };
      }
      return this;
    };
  }
  setCustomAttributes(customAttributes) {
    this.__customAttributes = customAttributes;
    return this;
  }
  unique(isUnique) {
    return super.unique(isUnique);
  }
  allowNull(isNull) {
    return super.allowNull(isNull);
  }
  allowBlank(isBlank) {
    if (isBlank === void 0) isBlank = true;
    this.__allowBlank = isBlank;
    return this;
  }
  /**
  * This method is used to create an index on the database for this field.
  */
  dbIndex(isDbIndex) {
    return super.dbIndex(isDbIndex);
  }
  underscored(isUnderscored) {
    return super.underscored(isUnderscored);
  }
  primaryKey(isPrimaryKey) {
    return super.primaryKey(isPrimaryKey);
  }
  auto(isAuto) {
    return super.auto(isAuto);
  }
  default(defaultValue) {
    return super.default(defaultValue);
  }
  databaseName(databaseName) {
    return super.databaseName(databaseName);
  }
  /**
  * This method can be used to override the type of a field. This is useful for library
  * maintainers that want to support a custom field type not supported by palmares.
  *
  * ### Note
  * - Your library should provide documentation of the fields that are supported.
  * - This should be used alongside the `_setPartialAttributes` method and `_setNewBuilderMethods`.
  * Instead of making users type NameOfYourField.new(), you should create a function that calls .new and creates
  * a new instance of the field for them.
  * - TDefinitions exists on type-level only, in runtime, it's not a guarantee of nothing. If TDefinitions
  * sets unique to true, it's up to you to do `NameOfYourField.new().unique()`, because otherwise it will be false
  */
  static overrideType(args) {
    return super._overrideType(args);
  }
  static new(..._args) {
    return new this(..._args);
  }
};
export {
  TextField,
  text
};
