/**
 * `abstract-service.ts`
 * - common service design pattern to build micro-service backend.
 *
 * @author      Tim Hong <tim@lemoncloud.io>
 * @date        2021-02-23 initial version
 * @author      Steve <steve@lemoncloud.io>
 * @date        2022-02-18 optimized search w/ ES6.8
 * @date        2022-02-22 optimized w/ `lemon-core#3.0` and `@elastic/elasticsearch`
 * @date        2022-02-24 use `$id` in elastic-search as `_id` in dynamo-table.
 * @date        2022-03-15 optimized w/ `AbstractProxy`
 * @date        2022-03-17 optimized w/ `lemon-core#3.0.2` and use `env.ES6_DOCTYPE`
 * @date        2022-03-31 optimized w/ unit test spec.
 * @date        2022-05-19 optimized `CacheService` w/ typed key.
 *
 * @origin      see `lemon-accounts-api/src/service/core-service.ts`
 * @copyright   (C) 2021 LemonCloud Co Ltd. - All Rights Reserved.
 */
import { AbstractManager, CacheService, CoreModel, CoreModelFilterable, DynamoOption, DynamoStreamEvent, Elastic6Option, Elastic6QueryService, Elastic6Service, GeneralKeyMaker, NextContext, NextIdentityAccess, StorageMakeable } from '../cores/';
import elasticsearch from '@elastic/elasticsearch';
/**
 * authentication helper - get identity-id from context
 * @param context the current request context.
 */
export declare function asIdentityId(context: NextContext): string | undefined;
/**
 * extract field names from models
 * - only fields start with lowercase, or all upper.
 */
export declare const filterFields: (fields: string[], base?: string[]) => string[];
/**
 * interface `ModelSynchronizer`
 */
export interface ModelSynchronizer<T extends CoreModel<string> = CoreModel<string>> {
    /**
     * callback for filtering items
     * @param id
     * @param item
     */
    filter?(id: string, item: T): boolean;
    /**
     * callback invoked before synchronization
     * @param id
     * @param eventName
     * @param item
     * @param diff
     * @param prev
     */
    onBeforeSync?(id: string, eventName: DynamoStreamEvent, item: T, diff?: string[], prev?: T): Promise<void>;
    /**
     * callback invoked after synchronization
     * @param id
     * @param eventName
     * @param item
     * @param diff
     * @param prev
     */
    onAfterSync?(id: string, eventName: DynamoStreamEvent, item: T, diff?: string[], prev?: T): Promise<void>;
}
/**
 * abstract class `CoreService`
 * - common abstract to build user service
 *
 * @abstract
 */
export declare abstract class CoreService<Model extends CoreModel<ModelType>, ModelType extends string> extends GeneralKeyMaker<ModelType> implements StorageMakeable<Model, ModelType> {
    /** dynamo table name */
    readonly tableName: string;
    /** global index name of elasticsearch */
    readonly idName: string;
    /** (optional) current timestamp */
    protected current: number;
    /**
     * constructor
     * @param tableName     target table-name (or .yml dummy file-name)
     * @param ns            namespace of dataset
     * @param idName        must be `_id` unless otherwise
     */
    protected constructor(tableName?: string, ns?: string, idName?: string);
    /**
     * override current time
     */
    setCurrent: (current: number) => number;
    /**
     * get the current dynamo-options.
     */
    get dynamoOptions(): DynamoOption;
    /**
     * create storage-service w/ fields list.
     */
    makeStorageService<T extends Model>(type: ModelType, fields: string[], filter: CoreModelFilterable<T>): import("../cores/").TypedStorageService<T, ModelType>;
}
/**
 * class: `CoreManager`
 * - shared core manager for all model
 *
 * @abstract
 */
export declare abstract class CoreManager<Model extends CoreModel<ModelType>, ModelType extends string, Service extends CoreService<Model, ModelType>> extends AbstractManager<Model, Service, ModelType> {
    /**
     * constructor
     * @protected
     */
    protected constructor(type: ModelType, parent: Service, fields: string[], uniqueField?: string);
    /**
     * say hello()
     */
    hello: () => string;
    /**
     * get existence of model
     * @param id
     */
    exists(id: string): Promise<boolean>;
    /**
     * find model - retrieve or null
     * @param id model-id
     */
    find(id: string): Promise<Model | null>;
    /**
     * get model by key
     * @param key global id(like primary-key)
     */
    findByKey(key: string): Promise<Model | null>;
    /**
     * batch get models
     * - retrieve multi models per each id
     * - must be matched with idList in sequence order.
     *
     * @param idList list of id
     * @param parrallel (optional) in parrallel size
     */
    getMulti(idList: string[], parrallel?: number): Promise<(Model | null)[]>;
    /**
     * batch get models in map by idName
     */
    getMulti$(idList: string[], idName?: string, parrallel?: number): Promise<{
        [id: string]: Model;
    }>;
    /**
     * get by unique field value
     * @param uniqueValue
     */
    getByUniqueField(uniqueValue: string): Promise<Model>;
    /**
     * find model by unique field value - retrieve or null
     * @param uniqueValue
     */
    findByUniqueField(uniqueValue: string): Promise<Model | null>;
    /**
     * prepare model
     *  - override `AbstractManager.prepare()`
     */
    prepare(id: string, $def?: Model, isCreate?: boolean): Promise<Model>;
    /**
     * update model
     *  - override 'AbstractManager.insert()'
     *
     * @deprecated use `AbstractProxy`
     */
    insert(model: Model, initSeq?: number): Promise<Model>;
    /**
     * create or update model
     * @param id    model id
     * @param model model data
     */
    save(id: string, model: Model): Promise<Model>;
    /**
     * update model
     *  - override 'AbstractManager.update()'
     */
    update(id: string, model: Model, $inc?: Model): Promise<Model>;
    /**
     * update or create model
     *  - override 'AbstractManager.updateOrCreate()'
     */
    updateOrCreate(id: string, model: Model, $inc?: Model): Promise<Model>;
    /**
     * delete model
     *  - override 'AbstractManager.delete()'
     */
    delete(id: string, destroy?: boolean): Promise<Model>;
    /**
     * prepare default-model when creation
     * @param $def  base-model
     */
    protected prepareDefault($def: Model): Model;
    /**
     * update lookup and delete old one if exists
     */
    protected updateLookup(id: string, model: Model, $org?: Model): Promise<void>;
}
/**
 * proxy of manager
 * - save model internally, and update only if changed properties.
 * Model extends CoreModel<ModelType>, ModelType extends string
 */
export declare class ManagerProxy<Model extends CoreModel<ModelType>, Manager extends CoreManager<Model, ModelType, CoreService<Model, ModelType>>, ModelType extends string = string> {
    readonly $mgr: Manager;
    constructor(proxy: AbstractProxy<string, CoreService<Model, ModelType>>, mgr: Manager);
    /**
     * store the origin model.
     * - `null` means `404 not found`
     */
    protected readonly _org: {
        [key: string]: Model;
    };
    /**
     * store the updated one.
     */
    protected readonly _new: {
        [key: string]: Model;
    };
    /**
     * get storage linked.
     */
    get storage(): import("../cores/").TypedStorageService<Model, ModelType>;
    /**
     * read the origin node (cloned not to change).
     */
    org(id: string, raw?: boolean): Model;
    /**
     * check if already read.
     */
    has(id: string): boolean;
    /**
     * read the node.
     * @param id object-id
     * @param defaultOrThrow (optional) create if not exists, or flag to throw error
     */
    get(id: string, defaultOrThrow?: Model | boolean): Promise<Model>;
    /**
     * 객체 정규화 시킴.
     * - null 에 대해서는 특별히 처리.
     */
    normal: (N: Model) => Model;
    /**
     * override w/ model
     * @param $org the origin model by `.get(id)`
     * @param model the new model.
     */
    override: ($org: Model, model: Model) => Model;
    /**
     * update the node.
     */
    set(id: string, model: Model): Promise<Model>;
    /**
     * increment the field of Object[id]
     * !WARN! this incremented properties should NOT be updated later.
     */
    inc(id: string, model: Model): Promise<Model>;
    /**
     * get all the updated node.
     *
     * @param onlyUpdated flag to return the only updated set. (useful to check whether to update really!)
     */
    alls(onlyUpdated?: boolean, onlyValid?: boolean): {
        [key: string]: Model;
    };
}
/**
 * class: `AbstractProxy`
 * - common abstract based class for Proxy
 */
export declare abstract class AbstractProxy<U extends string, T extends CoreService<CoreModel<U>, U>> {
    /** parrallel factor */
    readonly parrallel: number;
    /** (internal) current context */
    readonly context: NextContext;
    /** (internal) backend-service */
    readonly service: T;
    /** (internal) cache service instance */
    readonly cache?: CacheService;
    /**
     * constructor of proxy.
     * @param service user service instance
     * @param parrallel parrallel count (default 2)
     * @param cacheScope prefix of cache-key (like `lemon:SS:` or `lemon:SS:user`)
     */
    constructor(context: NextContext, service: T, parrallel?: number, cacheScope?: string);
    /**
     * say hello().
     */
    hello: () => string;
    /**
     * list of manager-proxy
     */
    protected _proxies: ManagerProxy<any, any>[];
    /**
     * get all proxies in list.
     */
    protected get allProxies(): ManagerProxy<any, any, string>[];
    /**
     * register this.
     *
     * @return size of proxies.
     */
    register(mgr: ManagerProxy<any, any>): number;
    /**
     * save all updates by each proxies.
     * - 업데이트할 항목을 모두 저장함
     *
     * @param options running parameters.
     */
    saveAllUpdates(options?: {
        /** (optional) the parrallel factor  */
        parrallel?: number;
        /** (optional) flag to use only valid value (not null) (default true) */
        onlyValid?: boolean;
    }): Promise<any[]>;
    /**
     * report via slack.
     */
    report: (title: string, data: any) => Promise<string>;
    /**
     * featch identity-acess from `lemon-accounts-api`
     */
    protected fetchIdentityAccess(identityId: string, domain?: string): Promise<{
        identityId: string;
        $identity: NextIdentityAccess<any>;
    }>;
    /**
     * the cached identity model
     */
    protected _identity: {
        [key: string]: NextIdentityAccess;
    };
    /**
     * fetch(or load) identity.
     *
     * @param identityId id to find
     * @param force (optional) force to reload if not available
     * @returns the cached identity-access
     */
    getIdentity$(identityId: string, force?: boolean): Promise<NextIdentityAccess>;
    /**
     * get current identity-id
     */
    getCurrentIdentityId(throwable?: boolean): Promise<string>;
    /**
     * get the current identity object (or throw access-error)
     */
    getCurrentIdentity$(throwable?: boolean): Promise<NextIdentityAccess>;
}
/**
 * type `SearchResult`
 */
export interface SearchResult<T, U = any> {
    /**
     * total count of items searched
     */
    total: number;
    /**
     * item list
     */
    list: T[];
    /**
     * pagination cursor
     */
    last?: string[];
    /**
     * aggregation result
     */
    aggregations?: U;
}
/**
 * class `Elastic6Synchronizer`
 * - listen DynamoDBStream events and index into Elasticsearch
 */
export declare class Elastic6Synchronizer {
    /**
     * model synchronizer map
     * @private
     */
    private readonly synchronizerMap;
    /**
     * default model synchronizer
     * @private
     */
    private readonly defModelSynchronizer;
    /**
     * constructor
     * @param elastic       elastic6-service instance
     * @param dynamoOptions dynamo options
     */
    constructor(elastic: Elastic6Service, dynamoOptions: DynamoOption | {
        tableName: string;
    });
    /**
     * set synchronizer for the model
     * @param type the model-type
     * @param handler (optional) custom synchronizer.
     */
    enableSynchronization(type: string, handler?: ModelSynchronizer): void;
    /**
     * internal callback for filtering
     * @private
     */
    private filter;
    /**
     * internal callback on before synchronization
     * @private
     */
    private onBeforeSync;
    /**
     * internal callback on after synchronization
     * @private
     */
    private onAfterSync;
}
/**
 * class `ElasticInstance`
 * - to manipulate the shared Elasticsearch resources.
 */
export declare class Elastic6Instance {
    /**
     * Elasticsearch client
     */
    readonly client?: elasticsearch.Client;
    /**
     * Elastic6Service instance
     */
    readonly elastic?: Elastic6Service;
    /**
     * Elastic6QueryService instance
     */
    readonly query?: Elastic6QueryService<any>;
    /**
     * Elastic6Synchronizer instance
     */
    readonly synchronizer?: Elastic6Synchronizer;
    /**
     * default constructor
     */
    constructor({ endpoint, indexName, esVersion, esDocType, tableName, autocompleteFields, }: {
        /** url endpoint */
        endpoint: string;
        /** name of index */
        indexName: string;
        /** ES engine version(6.2 ~ 7.x) */
        esVersion: string;
        /** doc-type (only valid under 6.2) */
        esDocType: string;
        /** dynamo-table to sync */
        tableName: string;
        /** field to make auto-complele */
        autocompleteFields: string[];
    });
    /**
     * read the current elastic6-option.
     */
    get options(): Elastic6Option;
    /**
     * create Elasticsearch index w/ custom settings
     */
    createIndex(): Promise<any>;
    /**
     * destroy Elasticsearch index
     */
    destroyIndex(): Promise<any>;
    /**
     * display index settings and mappings
     */
    describeIndex(): Promise<any>;
    /**
     * multi get
     * @param _ids  _id list
     */
    mget<T>(_ids: string[]): Promise<(T | null)[]>;
    /**
     * search raw query
     * @param body          Elasticsearch Query DSL
     * @param params        see 'search_type' in Elasticsearch documentation
     */
    search<T>(body: any, params?: {
        indexName?: string;
        searchType?: 'query_then_fetch' | 'dfs_query_then_fetch';
    }): Promise<SearchResult<T>>;
    /**
     * create async generator that yields items queried until last
     * @param body          Elasticsearch Query DSL
     * @param searchType    see 'search_type' in Elasticsearch documentation
     */
    generateSearchResult<T>(body: any, searchType?: 'query_then_fetch' | 'dfs_query_then_fetch'): AsyncGenerator<T[], void, unknown>;
}
/**
 * from Elasticsearch document to model item
 * - replace the elastic's `$id` field to `_id` of dynamo-table.
 *
 * @param _source from elastic-search
 * @param idName (optional) global id of elastic. (default is `$id`)
 */
export declare function sourceToItem<T>(_source: T, idName?: string): T;
/**
 * const `$ES6`
 * - default instance as a singleton by env configuration.
 */
export declare const $ES6: {
    /**
     * Elasticsearch client
     */
    readonly client?: elasticsearch.Client;
    /**
     * Elastic6Service instance
     */
    readonly elastic?: Elastic6Service;
    /**
     * Elastic6QueryService instance
     */
    readonly query?: Elastic6QueryService<any>;
    /**
     * Elastic6Synchronizer instance
     */
    readonly synchronizer?: Elastic6Synchronizer;
    /**
     * read the current elastic6-option.
     */
    readonly options: Elastic6Option;
    /**
     * create Elasticsearch index w/ custom settings
     */
    createIndex(): Promise<any>;
    /**
     * destroy Elasticsearch index
     */
    destroyIndex(): Promise<any>;
    /**
     * display index settings and mappings
     */
    describeIndex(): Promise<any>;
    /**
     * multi get
     * @param _ids  _id list
     */
    mget<T>(_ids: string[]): Promise<T[]>;
    /**
     * search raw query
     * @param body          Elasticsearch Query DSL
     * @param params        see 'search_type' in Elasticsearch documentation
     */
    search<T_1>(body: any, params?: {
        indexName?: string;
        searchType?: 'query_then_fetch' | 'dfs_query_then_fetch';
    }): Promise<SearchResult<T_1, any>>;
    /**
     * create async generator that yields items queried until last
     * @param body          Elasticsearch Query DSL
     * @param searchType    see 'search_type' in Elasticsearch documentation
     */
    generateSearchResult<T_2>(body: any, searchType?: 'query_then_fetch' | 'dfs_query_then_fetch'): AsyncGenerator<T_2[], void, unknown>;
};
