import { ApplyStrategy, CastOptions } from '../utils/cast-strategy';
import { ModelMetadata } from './interfaces/model-metadata.interface';
import { removeOptions, saveOptions } from './model.types';
import { PopulateFieldsType, PopulateOptionsType } from './populate.types';
type CleanDocument = Omit<Document, '$' | '$isNew'>;
export type IDocument<T = any> = CleanDocument & T;
/**
 * Document class represents a database document and provides useful methods to work with.
 *
 * @example
 * ```javascript
 * import { connect, model } from "ottoman";
 * connect("couchbase://localhost/travel-sample@admin:password");
 *
 * // Create an `User` model
 * const User = model('User', { name: String });
 *
 * // Create a document from the `User` Model
 * const jane = new User({ name: "Jane Doe" })
 * ```
 */
export declare abstract class Document {
    #private;
    /**
     * @ignore
     */
    [key: string]: any;
    /**
     * @ignore
     */
    protected constructor(data: any, options?: CastOptions);
    /**
     * @ignore
     */
    get $(): ModelMetadata;
    /**
     * Returns id value, useful when working with dynamic ID_KEY.
     *
     * @example
     * ```javascript
     *   console.log(user._getId()); // 'userId'
     *   console.log(user.id); // 'userId'
     * ```
     */
    _getId(): string;
    /**
     * Returns id key.
     */
    _getIdField(): string;
    /**
     * Saves or Updates the document.
     *
     * @example
     * ```javascript
     * const user = new User({ name: "John Doe" }); //user document created, it's not saved yet
     *
     * await user.save(); // user saved into the DB
     *
     * // You also can force save function to only create new Documents by passing true as argument
     * await user.save(true); // ensure to execute a insert operation
     * ```
     */
    save(onlyCreate?: boolean, options?: saveOptions): Promise<any>;
    /**
     * Removes the document from the database.
     *
     * @example
     * ```javascript
     * const user = User.findById('userId')
     *
     * await user.remove();
     * ```
     */
    remove(options?: removeOptions): Promise<any>;
    /**
     * Allows to load document references.
     *
     *
     * @example
     * Getting context to explain populate.
     * ```typescript
     * // Defining the schemas
     * const addressSchema = new Schema({
     *   address: String,
     * });
     * const personSchema = new Schema({
     *   name: String,
     *   age: Number,
     *   address: { type: addressSchema, ref: 'Address' },
     * });
     * const companySchema = new Schema({
     *   president: { type: personSchema, ref: 'Person' },
     *   ceo: { type: personSchema, ref: 'Person' },
     *   name: String,
     *   workers: [{ type: personSchema, ref: 'Person' }],
     * });
     *
     * // Initializing the models
     * const Address = model('Address', addressSchema);
     * const Person = model('Person', personSchema);
     * const Company = model('Company', companySchema);
     *
     * // Adding some data
     * const johnAddress = await Address.create({ address: '13 Washington Square S, New York, NY 10012, USA' });
     * const john = await Person.create({ name: 'John Smith', age: 52, address: johnAddress });
     *
     * const janeAddress = await Address.create({ address: '55 Clark St, Brooklyn, NY 11201, USA' });
     * const jane = await Person.create({ name: 'Jane Doe', age: 45, address: janeAddress });
     *
     * const company = await Company.create({ name: 'Space X', president: john, ceo: jane });
     *
     *
     * // Getting saved company data
     * const spaceX = await Company.findById(company.id);
     * console.log(`Company: `, company);
     * ```
     *
     * Will get:
     * ```
     * Company: {
     *     name: 'Space X',
     *     president: '50e85ac9-5b4f-4587-aeb6-b287527794c9',
     *     ceo: '32c2e85a-cc91-4db2-935f-f7d2768168de',
     *     id: 'd59efbdf-4b7e-4d2f-a986-6e8451f22822',
     *     _type: 'Company'
     * }
     * ```
     *
     * Now we will see how the _populate methods works.
     * ```typescript
     * const result = await spaceX._populate('ceo');
     * console.log(`Result: `, result);
     * ```
     * ```
     * Result: {
     *   name: 'Space X',
     *   president: '50e85ac9-5b4f-4587-aeb6-b287527794c9',
     *   ceo: {
     *     name: 'Jane Doe',
     *     age: 45,
     *     address: '235dd441-b445-4b88-b6aa-2ce35a958a32',
     *     id: '32c2e85a-cc91-4db2-935f-f7d2768168de',
     *     _type: 'Person'
     *   },
     *   id: 'd59efbdf-4b7e-4d2f-a986-6e8451f22822',
     *   _type: 'Company'
     * }
     * ```
     *
     * Can also pass an array or a string separated by a comma
     * ```typescript
     * const result = await spaceX._populate('ceo,president');
     * // or
     * const result = await spaceX._populate(['ceo', 'president']);
     * console.log(`Result: `, result);
     * ```
     * ```
     * Result: {
     *   name: 'Space X',
     *   president: {
     *     name: 'John Smith',
     *     age: 52,
     *     address: 'bc7ea8a8-8d1c-4ab6-990c-d3a0163f7e10',
     *     id: '50e85ac9-5b4f-4587-aeb6-b287527794c9',
     *     _type: 'Person'
     *   },
     *   ceo: {
     *     name: 'Jane Doe',
     *     age: 45,
     *     address: '235dd441-b445-4b88-b6aa-2ce35a958a32',
     *     id: '32c2e85a-cc91-4db2-935f-f7d2768168de',
     *     _type: 'Person'
     *   },
     *   id: 'd59efbdf-4b7e-4d2f-a986-6e8451f22822',
     *   _type: 'Company'
     * }
     * ```
     *
     * If you want to get only a portion of the object
     * ```typescript
     * const result = await spaceX._populate({
     *   ceo: ['age', 'address'], // or 'age,addres'
     *   president: 'name',
     * });
     * console.log(`Result: `, result);
     * ```
     * ```
     * Result: {
     *   name: 'Space X',
     *   president: { name: 'John Smith' },
     *   ceo: { age: 45, address: '235dd441-b445-4b88-b6aa-2ce35a958a32' },
     *   id: 'd59efbdf-4b7e-4d2f-a986-6e8451f22822',
     *   _type: 'Company'
     * }
     * ```
     *
     * Now let's to go deeper
     * ```typescript
     * const result = await spaceX._populate(
     *   {
     *     ceo: {
     *       select: 'age,id', // remember you can use ['age','address']
     *       populate: 'address', // will populate all the fields
     *     },
     *     president: {
     *       select: 'name',
     *       populate: {
     *         address: 'address', // will populate address field only
     *       },
     *     },
     *   },
     *   2, // for populate up to the second level
     * );
     * console.log(`Result: `, result);
     * ```
     * ```
     * Result: {
     *   name: 'Space X',
     *   president: {
     *     name: 'John Smith',
     *     address: { address: '13 Washington Square S, New York, NY 10012, USA' }
     *   },
     *   ceo: {
     *     age: 45,
     *     id: '32c2e85a-cc91-4db2-935f-f7d2768168de',
     *     address: {
     *       address: '55 Clark St, Brooklyn, NY 11201, USA',
     *       id: '235dd441-b445-4b88-b6aa-2ce35a958a32',
     *       _type: 'Address'
     *     }
     *   },
     *   id: 'd59efbdf-4b7e-4d2f-a986-6e8451f22822',
     *   _type: 'Company'
     * }
     *```
     * Below is another way through the find functions
     * ```typescript
     * const result = await Company.findOne(
     *   { name: 'Space X' },
     *   {
     *     select: 'president,ceo',
     *     populate: {
     *       president: { select: 'address,id', populate: 'address' },
     *       ceo: { select: ['age', 'name'], populate: { address: { select: 'id' } } },
     *     },
     *     populateMaxDeep: 2,
     *   },
     * );
     * console.log(`Result: `, result);
     * ```
     * ```
     * Result: {
     *   ceo: {
     *     age: 45,
     *     name: 'Jane Doe',
     *     address: { id: '235dd441-b445-4b88-b6aa-2ce35a958a32' }
     *   },
     *   president: {
     *     address: {
     *       address: '13 Washington Square S, New York, NY 10012, USA',
     *       id: 'bc7ea8a8-8d1c-4ab6-990c-d3a0163f7e10',
     *       _type: 'Address'
     *     },
     *     id: '50e85ac9-5b4f-4587-aeb6-b287527794c9'
     *   }
     * }
     * ```
     */
    _populate(fieldsName?: PopulateFieldsType, options?: PopulateOptionsType): Promise<this>;
    /**
     * Reverts population. Switches back document reference.
     *
     * @example
     * To get in context about the Card and Issue Models [see the populate example.](/docs/api/classes/document.html).
     * ```javascript
     * const card = await Card.findById(cardId);
     * console.log(card.issues); // ['issueId']
     *
     * await card._populate('issues')
     * console.log(card.issues); // [{ id: 'issueId', title: 'Broken card' }]
     *
     * card._depopulate('issues')
     * console.log(card.issues); // ['issueId']
     * ```
     */
    _depopulate(fieldsName: string | string[]): this;
    /**
     * Allows to know if a document field is populated.
     *
     * @example
     * To get in context about the Card and Issue Models [see the populate example.](/docs/api/classes/document.html).
     * ```javascript
     * const card = await Card.findById(cardId);
     * console.log(card.issues); // ['issueId']
     * console.log(card._populated('issues')); // false
     *
     * await card._populate('issues')
     * console.log(card.issues); // [{ id: 'issueId', title: 'Broken card' }]
     * console.log(card._populated('issues')); // true
     * ```
     */
    _populated(fieldName: string): boolean;
    /**
     * Allows to easily apply data from an object to current document.
     *
     * @example
     * ```typescript
     * const user = new User({ name: "John Doe" });
     *
     * user._applyData({ name: "Jane Doe" });
     * console.log(user) // { name: "Jane Doe" }
     * ```
     *
     * @example With strategies on immutable properties
     * ```typescript
     * const User = model('Card', { name: { type: String, immutable: true } });
     * const user = new User({ name: 'John Doe' });
     *
     *  // with strategy:false is like above example
     *  user._applyData({ name: 'Jane Doe' }, false);
     *  console.log(user); // { name: "Jane Doe" }
     *
     *  // with strategy:true remains immutable
     *  user._applyData({ name: 'Jane Doe' }, true);
     *  console.log(user); // { name: "John Doe" }
     *
     *  // trying to update it directly
     *  user.name = 'Jane Doe';
     *  console.log(user); // { name: "John Doe" }
     *
     *  // with strategy:CAST_STRATEGY.THROW
     *  user._applyData({ name: 'Jane Doe' }, CAST_STRATEGY.THROW);
     *  // ImmutableError: Field 'name' is immutable and current cast strategy is set to 'throw'
     * ```
     */
    _applyData(data: any, strategy?: ApplyStrategy): this;
    /**
     * Runs schema validations over current document.
     * @example
     * ```javascript
     * const user = new User( { name: "John Doe" } );
     *
     * try {
     *   await user._validate()
     * } catch(errors) {
     *   console.log(errors)
     * }
     * ```
     */
    _validate(): any;
    /**
     * Returns a Javascript object with data
     */
    toObject(): this;
    /**
     * Returns a Javascript object to be serialized to JSON
     */
    toJSON(): this;
    /**
     * Encapsulate logic for toObject and toJson
     * @ignore
     */
    $toObject(): this;
    /**
     * Boolean flag specifying if the document is new.
     * @example
     * ```typescript
     * const CardSchema = new Schema({
     *   cardNumber: { type: String, immutable: true },
     *   zipCode: String,
     * });
     *
     * // Create model
     * const Card = model('Card', CardSchema);
     *
     * // Create document
     * const myCard = new Card({ cardNumber: '4321 4321 4321 4321', zipCode: '43210' });
     * myCard.$isNew; // true
     *
     * // Save document
     * const myCardSaved = await myCard.save();
     * myCardSaved.$isNew; // false
     * ```
     */
    get $isNew(): boolean;
}
export {};
