import { ArraySchema } from './schema/array';
import { ObjectSchema } from './schema/object';
import type { Schema } from './schema/schema';
import type { DefinitionsOfSchemaType, ExtractTypeFromObjectOfSchemas } from './schema/types';
import type { InferModel, Model, ModelFields } from '@palmares/databases';
/**
 * Different from other schemas, this function is a factory function that returns either an ObjectSchema or an
 * ArraySchema. The idea is to build the schema of a model dynamically based on its fields.
 *
 * Another feature is that it can automatically add the foreign key relation to the schema, but for that you need to
 * define the fields of the related model in the fields object.
 *
 * For example: A User model have a field `companyId` that is a ForeignKeyField to the Company model. The `relationName`
 * is the direct relation from the User model to the Company model, and the `relatedName` is the reverse relation from
 * the Company model to the User model. If you define the fieldName as either the relatedName or the relationName it
 * will fetch the data automatically.
 *
 * **Important**: We build the schema dynamically but also lazily, if you don't try to parse or validate the schema, it
 * won't be built. After the first time it's built, it's cached and never built again.
 *
 * **Important 2**: If you want to use the automatic relation feature, you need to define guarantee that the foreignKey
 * field fieldName exists on `show` array, or that it doesn't exist on `omit` array.
 *
 * Like: `{ options: { show: ['id', 'name', 'companyId'] }}` or `{ options: { omit: ['id'] }}` it **will work**.
 *
 * If you do `{ options: { show: ['id', 'name'] }}` or `{ options: { omit: ['companyId']} }` it **won't work**.
 *
 * **Important 3**: If you want to return an array instead of an object, you need to pass the `many` option as true.
 *
 * @example
 * ```typescript
 * import { auto, choice, foreignKey, Model, define } from '@palmares/databases';
 * import * as p from '@palmares/schemas';
 *
 * const Company = define('Company', {
 *   fields: {
 *     id: auto(),
 *     name: text(),
 *   },
 *   options: {
 *     tableName: 'company',
 *   }
 * });
 *
 * class User extends Model<User>() {
 *    fields = {
 *     id: auto(),
 *     type: choice({ choices: ['user', 'admin'] }),
 *     companyId: foreignKey({
 *        relatedTo: Company,
 *        relationName: 'company',
 *        relatedName: 'usersOfCompany',
 *        toField: 'id',
 *        onDelete: 'CASCADE',
 *      }),
 *   }
 *
 *   options = {
 *     tableName: 'user',
 *   }
 * }
 *
 * const userSchema = p.modelSchema(User, {
 *   fields: {
 *      company: p.modelSchema(Company).optional({ outputOnly: true });
 *   },
 *   show: ['type', 'companyId'], // 'companyId' is required for the automatic relation to work, otherwise it won't show
 *   omitRelation: ['company']
 * });
 *
 * const companySchema = p.modelSchema(Company, {
 *   fields: {
 *      usersOfCompany: p.modelSchema(User, { many: true }).optional({ outputOnly: true });
 *   },
 *   // The `companyId` field on the 'User' model is tied to the `id` field on the 'Company' model so 'id' is required.
 *   show: ['id', 'type'] * });
 *```
 * @param model - The model that you want to build the schema from.
 * @param options - The options to build the schema.
 * @param options.ignoreExtraneousFields - If you want to ignore extraneous fields set this to true.
 * @param options.engineInstance - What engine instance you want to use to fetch the data. Defaults to the first one.
 * @param options.omitRelation - Fields that you want to omit from the relation. For example, on the example above, on
 * the `userSchema` you can omit the `companyId` field from the relation by just passing `['company']`, on the
 * `companySchema`  you can omit the `id` field from company by passing `['usersOfCompany']`.
 *
 * @param options.fields - Extra fields that you want to add to the schema. If it has the same name as the model field,
 * We will not create a schema for that field and use the one you have defined here.
 * @param options.omit - Fields that you want to omit from the schema. If that is defined, we ignore `show` option.
 * @param options.show - Fields that you want to show on the schema. If that is defined, we ignore `omit` option.
 * @param options.many - If you want to return an array instead of an object, set this to true. With that we create
 * an ArraySchema instead of an ObjectSchema.
 *
 * @returns - If you pass the `many` option as true, we return an ArraySchema, otherwise we return an ObjectSchema.
 */
export declare function modelSchema<TModel extends ReturnType<typeof Model>, const TOmit extends readonly (keyof ModelFields<InstanceType<TModel>>)[] | undefined[] = undefined[], const TShow extends readonly (keyof ModelFields<InstanceType<TModel>>)[] | undefined[] = undefined[], TMany extends boolean = false, TFields extends Record<any, Schema<any, DefinitionsOfSchemaType>> | undefined = undefined, TAllModelFieldsRead = InferModel<InstanceType<TModel>, 'read'>, TAllModelFieldsCreate = InferModel<InstanceType<TModel>, 'create'>, TDefinitionsOfSchemaType extends DefinitionsOfSchemaType = DefinitionsOfSchemaType, TFieldsOnModelRead = TOmit extends undefined[] ? TShow extends undefined[] ? TAllModelFieldsRead : Pick<TAllModelFieldsRead, TShow[number] extends keyof TAllModelFieldsRead ? TShow[number] : never> : Omit<TAllModelFieldsRead, TOmit[number] extends keyof TAllModelFieldsRead ? TOmit[number] : never>, TFieldsOnModelCreateOrUpdate = TOmit extends undefined[] ? TShow extends undefined[] ? TAllModelFieldsCreate : Pick<TAllModelFieldsCreate, TShow[number] extends keyof TAllModelFieldsCreate ? TShow[number] : never> : Omit<TAllModelFieldsCreate, TOmit[number] extends keyof TAllModelFieldsCreate ? TOmit[number] : never>, TReturnType extends {
    input: any;
    output: any;
    validate: any;
    internal: any;
    representation: any;
} = {
    input: TFields extends undefined ? TFieldsOnModelCreateOrUpdate : Omit<TFieldsOnModelCreateOrUpdate, keyof ExtractTypeFromObjectOfSchemas<TFields extends undefined ? {} : TFields, 'input'>> & ExtractTypeFromObjectOfSchemas<TFields extends undefined ? {} : TFields, 'input'>;
    output: TFields extends undefined ? TFieldsOnModelRead : Omit<TFieldsOnModelRead, keyof ExtractTypeFromObjectOfSchemas<TFields extends undefined ? {} : TFields, 'output'>> & ExtractTypeFromObjectOfSchemas<TFields extends undefined ? {} : TFields, 'output'>;
    internal: TFields extends undefined ? TFieldsOnModelCreateOrUpdate : Omit<TFieldsOnModelCreateOrUpdate, keyof ExtractTypeFromObjectOfSchemas<TFields extends undefined ? {} : TFields, 'internal'>> & ExtractTypeFromObjectOfSchemas<TFields extends undefined ? {} : TFields, 'internal'>;
    representation: TFields extends undefined ? TFieldsOnModelRead : Omit<TFieldsOnModelRead, keyof ExtractTypeFromObjectOfSchemas<TFields extends Record<any, Schema<any, DefinitionsOfSchemaType>> ? TFields : {}, 'representation'>> & ExtractTypeFromObjectOfSchemas<TFields extends Record<any, Schema<any, DefinitionsOfSchemaType>> ? TFields : {}, 'representation'>;
    validate: TFields extends undefined ? TFieldsOnModelCreateOrUpdate : Omit<TFieldsOnModelCreateOrUpdate, keyof ExtractTypeFromObjectOfSchemas<TFields extends Record<any, Schema<any, DefinitionsOfSchemaType>> ? TFields : {}, 'validate'>> & ExtractTypeFromObjectOfSchemas<TFields extends Record<any, Schema<any, DefinitionsOfSchemaType>> ? TFields : {}, 'validate'>;
}>(model: TModel, options?: {
    ignoreExtraneousFields?: boolean;
    engineInstance?: string;
    fields?: TFields;
    omit?: TOmit;
    show?: TShow;
    omitRelation?: readonly (keyof TFields)[];
    many?: TMany;
}): TMany extends true ? ArraySchema<{
    input: TReturnType['input'][];
    output: TReturnType['output'][];
    internal: TReturnType['internal'][];
    representation: TReturnType['representation'][];
    validate: TReturnType['validate'][];
}, TDefinitionsOfSchemaType, [
    ObjectSchema<{
        input: TReturnType['input'];
        output: TReturnType['output'];
        internal: TReturnType['internal'];
        representation: TReturnType['representation'];
        validate: TReturnType['validate'];
    }, TDefinitionsOfSchemaType, Record<any, any>>
]> : ObjectSchema<{
    input: TReturnType['input'];
    output: TReturnType['output'];
    internal: TReturnType['internal'];
    representation: TReturnType['representation'];
    validate: TReturnType['validate'];
}, TDefinitionsOfSchemaType, Record<any, any>>;
//# sourceMappingURL=model.d.ts.map