import { Observable, BehaviorSubject } from 'rxjs';
import * as types from 'blow-types';
import { IQuery, IQueryObject, IQueryWhere } from 'blow-query';
export interface IValidator {
    validate(data: any): Observable<IValidationResult>;
}
export interface IValidationResult {
    isValid: boolean;
    errors: any;
    getInvalidProperties(): any;
    getPropertyErrors(propertyName: string): any;
    toJSON(): any;
}
export interface IManager {
    attachModelToConnection(model: string | IBaseModelConstructor, connection: string | IConnection): any;
    hasConnection(connectionName: string): boolean;
    getConnection(connectionName: string): IConnection;
    defineConnection(options: IConnectionOptions): IConnection;
    hasModel(modelName: string): boolean;
    getModel(modelName: string): IBaseModelConstructor;
    defineModel(model: IBaseModelConstructor, options: IModelMetadataOptions, properties?: {
        [key: string]: IModelPropertyMetadataOptions;
    }, relations?: {
        [key: string]: IModelRelationMetadataOptions;
    }): void;
    init(): Observable<IManager>;
}
export interface IConnectionOptions extends IAdapterOptions {
    name: string;
    adapter: IAdapterConstructor;
    params?: any;
}
export interface IConnection {
    name: string;
    adapter: IAdapter;
    status: BehaviorSubject<string>;
    isConnected: boolean;
    init(): Observable<IConnection>;
    attach(model: IBaseModelConstructor): void;
}
export interface IModelRelationMetadataOptions {
    name: string;
    type: string;
    model: IPersistedModelConstructor;
    foreignKey: string;
    hidden: boolean;
}
export interface IModelRelationMetadata {
    name: string;
    type: string;
    model: IPersistedModelConstructor | string;
    foreignKey: string;
    hidden: boolean;
    apply(model: IPersistedModelConstructor): void;
}
export interface IModelPropertyMetadata {
    name: string;
    columnName: string;
    type: types.Type;
    default: () => any;
    id: boolean;
    index: boolean;
    hidden: boolean;
    validations: IterableIterator<any>;
    apply(model: IBaseModelConstructor): void;
}
export interface IModelPropertyMetadataOptions {
    name: string;
    type: any;
    default?: any;
    id?: boolean;
    columnName?: string;
    index?: boolean;
    hidden?: boolean;
    validations?: {
        [key: string]: any;
    };
}
export interface IModelMetadataOptions {
    name: string;
    connection?: string;
    pluralName?: string;
    autoId?: boolean;
}
export interface IModelMetadata {
    name: string;
    pluralName: string;
    autoId: boolean;
    properties: IterableIterator<IModelPropertyMetadata>;
    relations: IterableIterator<IModelRelationMetadata>;
    connectionName: string;
    idProperty: IModelPropertyMetadata;
    validationSchema: {
        [key: string]: any;
    };
    asyncValidationSchema: {
        [key: string]: any;
    };
    defineProperty(options: IModelPropertyMetadataOptions): void;
    buildPropertyId(name: string, type: any): void;
    getProperty(name: string): IModelPropertyMetadata;
    hasProperty(name: string): boolean;
    isAllowedProperty(name: string): boolean;
    defineRelation(options: IModelRelationMetadataOptions): void;
    apply(model: any): void;
}
export interface IBaseModelData {
    [field: string]: any;
}
export interface IBaseModelConstructor {
    new (data?: IBaseModelData): IBaseModel;
    metadata: IModelMetadata;
    ready: boolean;
    prototype: Object;
    validator: IValidator;
}
export interface IBaseModel {
    merge(data: IBaseModelData): IBaseModel;
    toJSON(withHidden?: boolean): IBaseModelData;
    toSafeJSON(): IBaseModelData;
    inspect(): IBaseModelData;
}
export interface IPersistedModelConstructor extends IBaseModelConstructor {
    new (data?: IBaseModelData): IPersistedModel;
    count(where?: IQueryWhere): Observable<number>;
    create(data: IBaseModelData | IPersistedModel): Observable<IPersistedModel>;
    destroy(where?: IQueryWhere): Observable<number>;
    destroyById(id: any): Observable<boolean>;
    exists(query: IQuery | IQueryObject): Observable<boolean>;
    find(query?: IQuery | IQueryObject): Observable<IPersistedModel>;
    findOne(query?: IQuery | IQueryObject): Observable<IPersistedModel>;
    findById(id: any): Observable<IPersistedModel>;
    findOrCreate(where: IQueryWhere, data: IBaseModelData): Observable<IPersistedModel>;
    update(where: IQueryWhere, data: IBaseModelData): Observable<number>;
    updateOrCreate(data: IBaseModelData | IPersistedModel): Observable<IPersistedModel>;
}
export interface IPersistedModel extends IBaseModel {
}
export interface IPersistedAdapterConstructor extends IAdapterConstructor {
}
export interface IPersistedAdapter extends IAdapter {
    count(metadata: IModelMetadata, where?: IQueryWhere): Observable<number>;
    create(metadata: IModelMetadata, data: any): Observable<any>;
    destroy(metadata: IModelMetadata, where?: IQueryWhere): Observable<number>;
    destroyById(metadata: IModelMetadata, id: any): Observable<boolean>;
    exists(metadata: IModelMetadata, id: any | IQueryObject): Observable<boolean>;
    find(metadata: IModelMetadata, query?: IQuery | IQueryObject): Observable<any>;
    findOne(metadata: IModelMetadata, query?: IQuery | IQueryObject): Observable<any>;
    findById(metadata: IModelMetadata, id: any): Observable<any>;
    findOrCreate(metadata: IModelMetadata, where: IQueryWhere, data: any): Observable<any>;
    update(metadata: IModelMetadata, where: IQueryWhere, data: any): Observable<number>;
    updateOrCreate(metadata: IModelMetadata, data: any): Observable<any>;
}
export interface IAdapterOptions {
    [key: string]: any;
}
export interface IAdapterConstructor {
    new (options: IAdapterOptions): IAdapter;
    init(options: IAdapterOptions): Observable<IAdapter>;
}
export interface IAdapter {
    idPropertyName: string;
    idPropertyType(): any;
    connect(): Observable<IAdapter>;
    toJSON(): {
        [key: string]: string;
    };
    inspect(): {
        [key: string]: string;
    };
}
export interface IHasManyRelation<T> {
    create(data: {
        [key: string]: any;
    } | T): Observable<T>;
    destroy(where?: IQueryWhere): Observable<number>;
    destroyById(id: any): Observable<boolean>;
    find(query?: IQuery | IQueryObject): Observable<T>;
    findById(id: any): Observable<T>;
}
export interface IBelongsToRelation<T> {
    (data: {
        [key: string]: any;
    } | T): Observable<T> | void;
}
