egg-orm-ts
Version:
Simple orm with Typeorm, for egg plugin.
1,741 lines (1,533 loc) • 48.1 kB
TypeScript
/// <reference types="node" />
import 'egg';
import 'egg-onerror';
import 'egg-session';
import 'egg-i18n';
import 'egg-watcher';
import 'egg-multipart';
import 'egg-security';
import 'egg-development';
import 'egg-logrotator';
import 'egg-schedule';
import 'egg-static';
import 'egg-jsonp';
import 'egg-view';
import accepts = require('accepts');
import EggCookies = require('egg-cookies');
import KoaApplication = require('koa');
import KoaRouter = require('koa-router');
import { EventEmitter } from 'events'
import { Readable } from 'stream';
import { Socket } from 'net';
import { IncomingMessage, ServerResponse } from 'http';
import { HttpClient, RequestOptions2 as RequestOptions } from 'urllib';
import {
EggCoreBase,
FileLoaderOption,
EggLoader as CoreLoader,
EggCoreOptions as CoreOptions,
EggLoaderOptions as CoreLoaderOptions,
BaseContextClass as CoreBaseContextClass,
} from 'egg-core';
import { EggLogger as Logger, EggLoggers, LoggerLevel as EggLoggerLevel, EggLoggersOptions, EggLoggerOptions, EggContextLogger } from 'egg-logger';
import {
DeepPartial,
FindConditions,
FindManyOptions,
FindOneOptions,
ObjectID,
ObjectLiteral,
QueryRunner,
Repository,
SaveOptions,
UpdateResult,
DeleteResult,
OrderByCondition,
} from 'typeorm';
import { AnySchema } from 'joi';
declare type DATA_TYPE = 'String' | 'Number' | 'Boolean' | 'Date' | 'Array' | 'Undefined' | 'Null' |
'Error' | 'Symbol' | 'Function' | 'Math' | 'RegExp' | 'HTMLDocument' | 'global';
declare type HTTP_CODE =
/* 1xx informational response */
/* 2xx success */
'SUCCESS_OK' | 'SUCCESS_CREATED' | 'SUCCESS_ACCEPTED' |
// 不常用
'NON_AUTHORITATIVE_INFORMATION' | 'NO_CONTENT' | 'RESET_CONTENT' | 'PARTIAL_CONTENT' |
/* 3xx redirection */
/* 4xx client errors */
'CLIENT_BAD_REQUEST' | 'CLIENT_UNAUTHORIZED' | 'CLIENT_FORBIDDEN' | 'CLIENT_NOT_FOUND' |
'CLIENT_METHOD_NOT_ALLOWED' | 'CLIENT_NOT_ACCEPTABLE' | 'CLIENT_PAYLOAD_TOO_LARGE' |
/* 5xx server errors */
'SERVER_INTERNAL_SERVER_ERROR' |
// 不常用
'NOT_IMPLEMENTED' | 'BAD_GATEWAY' | 'SERVICE_UNAVAILABLE' | 'GATEWAY_TIMEOUT' | 'HTTP_VERSION_NOT_SUPPORTED';
declare type HTTP_CODE_MESSAGE = { 200: '请求成功' } |
{ 201: '数据操作成功' } |
{ 202: '任务已经接受' } |
{ 203: '非权威内容' } |
{ 204: '请求已处理,无响应内容' } |
{ 205: '请求已处理,需重置内容' } |
{ 400: '异常请求' } |
{ 401: '未登录或者过期' } |
{ 403: '没有操作权限' } |
{ 404: '未找到资源' } |
{ 405: '请求方法错误' } |
{ 406: '响应格式不匹配' } |
{ 413: '请求内容过大' } |
{ 500: '服务器异常' } |
{ 502: '网关错误' } |
{ 501: '未实现' } |
{ 503: '服务不可用' } |
{ 504: '网关超时' } |
{ 505: '协议版本不支持' };
declare type BIZ_CODE = 'FAIL' | 'SUCCESS';
declare type OprValue = '!=' | '<' | '<=' | '>' | '>=' | '=' | '<>' | 'not in' | '!<>' |
'not between' | 'not' | 'lessThan' | 'lessThanOrEqual' | 'moreThan' | 'moreThanOrEqual' |
'equal' | 'between' | 'in' | 'any' | 'isNull' | 'iLike' | 'like' | 'raw';
declare type AdvanceCondition = {
[key: string]: {
opr: OprValue,
val: any,
};
};
declare type CriteriaParam<T> = string | string[] | number | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions<T>;
declare type ListParam<T> = FindConditions<T>[] | FindConditions<T> | ObjectLiteral | AdvanceCondition | string | FindManyOptions<T>;
/**
* 分页参数
* - current 默认 1
* - pageSize 默认 10
*/
declare type PageParam = {
current?: number;
pageSize?: number;
sort?: OrderByCondition;
};
// 成功标志
declare type SuccessFlag = {
success: boolean;
};
// 分页对象
declare type PageProps<Entity> = {
// Optional
totalPage: number;
current: number;
pageSize: number;
// Required
total: number;
data: Entity[];
// AntD table required
success: boolean;
};
declare module 'egg-orm-ts' {
export type EggLogger = Logger;
// plain object
type PlainObject<T = any> = { [key: string]: T };
// Remove specific property from the specific class
type RemoveSpecProp<T, P> = Pick<T, Exclude<keyof T, P>>;
export interface EggHttpClient extends HttpClient<RequestOptions> {}
interface EggHttpConstructor {
new (app: Application): EggHttpClient;
}
export interface EggContextHttpClient extends HttpClient<RequestOptions> {}
interface EggContextHttpClientConstructor {
new (ctx: Context): EggContextHttpClient;
}
/**
* BaseContextClass is a base class that can be extended,
* it's instantiated in context level,
* {@link Helper}, {@link Service} is extending it.
*/
export class BaseContextClass extends CoreBaseContextClass<Context, Application, EggAppConfig, IService> { // tslint:disable-line
/**
* logger
*/
protected logger: EggLogger;
}
export class Boot {
/**
* logger
* @member {EggLogger}
*/
protected logger: EggLogger;
/**
* The configuration of application
* @member {EggAppConfig}
*/
protected config: EggAppConfig;
/**
* The instance of agent
* @member {Agent}
*/
protected agent: Agent;
/**
* The instance of app
* @member {Application}
*/
protected app: Application;
}
export type RequestArrayBody = any[];
export type RequestObjectBody = PlainObject;
export interface Request extends KoaApplication.Request { // tslint:disable-line
/**
* detect if response should be json
* 1. url path ends with `.json`
* 2. response type is set to json
* 3. detect by request accept header
*
* @member {Boolean} Request#acceptJSON
* @since 1.0.0
*/
acceptJSON: boolean;
/**
* Request remote IPv4 address
* @member {String} Request#ip
* @example
* ```js
* this.request.ip
* => '127.0.0.1'
* => '111.10.2.1'
* ```
*/
ip: string;
/**
* Get all pass through ip addresses from the request.
* Enable only on `app.config.proxy = true`
*
* @member {Array} Request#ips
* @example
* ```js
* this.request.ips
* => ['100.23.1.2', '201.10.10.2']
* ```
*/
ips: string[];
protocol: string;
/**
* get params pass by querystring, all value are Array type. {@link Request#query}
* @member {Array} Request#queries
* @example
* ```js
* GET http://127.0.0.1:7001?a=b&a=c&o[foo]=bar&b[]=1&b[]=2&e=val
* this.queries
* =>
* {
* "a": ["b", "c"],
* "o[foo]": ["bar"],
* "b[]": ["1", "2"],
* "e": ["val"]
* }
* ```
*/
queries: PlainObject<string[]>;
/**
* get params pass by querystring, all value are String type.
* @member {Object} Request#query
* @example
* ```js
* GET http://127.0.0.1:7001?name=Foo&age=20&age=21
* this.query
* => { 'name': 'Foo', 'age': 20 }
*
* GET http://127.0.0.1:7001?a=b&a=c&o[foo]=bar&b[]=1&b[]=2&e=val
* this.query
* =>
* {
* "a": "b",
* "o[foo]": "bar",
* "b[]": "1",
* "e": "val"
* }
* ```
*/
query: PlainObject<string>;
body: any;
}
export interface Response extends KoaApplication.Response { // tslint:disable-line
/**
* read response real status code.
*
* e.g.: Using 302 status redirect to the global error page
* instead of show current 500 status page.
* And access log should save 500 not 302,
* then the `realStatus` can help us find out the real status code.
* @member {Number} Context#realStatus
*/
realStatus: number;
}
export type LoggerLevel = EggLoggerLevel;
/**
* egg app info
* @example
* ```js
* // config/config.default.ts
* import { EggAppInfo } from 'egg';
*
* export default (appInfo: EggAppInfo) => {
* return {
* keys: appInfo.name + '123456',
* };
* }
* ```
*/
export interface EggAppInfo {
pkg: any; // package.json
name: string; // the application name from package.json
baseDir: string; // current directory of application
env: EggEnvType; // equals to serverEnv
HOME: string; // home directory of the OS
root: string; // baseDir when local and unittest, HOME when other environment
}
type IgnoreItem = string | RegExp | ((ctx: Context) => boolean);
type IgnoreOrMatch = IgnoreItem | IgnoreItem[];
/** logger config of egg */
export interface EggLoggerConfig extends RemoveSpecProp<EggLoggersOptions, 'type'> {
/** custom config of coreLogger */
coreLogger?: Partial<EggLoggerOptions>;
/** allow debug log at prod, defaults to true */
allowDebugAtProd?: boolean;
/** disable logger console after app ready. defaults to `false` on local and unittest env, others is `true`. */
disableConsoleAfterReady?: boolean;
}
/** Custom Loader Configuration */
export interface CustomLoaderConfig extends RemoveSpecProp<FileLoaderOption, 'inject' | 'target'> {
/**
* an object you wanner load to, value can only be 'ctx' or 'app'. default to app
*/
inject?: 'ctx' | 'app';
/**
* whether need to load files in plugins or framework, default to false
*/
loadunit?: boolean;
}
export interface HttpClientBaseConfig {
/** Whether use http keepalive */
keepAlive?: boolean;
/** Free socket after keepalive timeout */
freeSocketKeepAliveTimeout?: number;
/** Free socket after request timeout */
freeSocketTimeout?: number;
/** Request timeout */
timeout?: number;
/** Determines how many concurrent sockets the agent can have open per origin */
maxSockets?: number;
/** The maximum number of sockets that will be left open in the free state */
maxFreeSockets?: number;
}
/** HttpClient config */
export interface HttpClientConfig extends HttpClientBaseConfig {
/** http.Agent */
httpAgent?: HttpClientBaseConfig;
/** https.Agent */
httpsAgent?: HttpClientBaseConfig;
/** Default request args for httpClient */
request?: RequestOptions;
/** Whether enable dns cache */
enableDNSCache?: boolean;
/** Enable proxy request, default is false. */
enableProxy?: boolean;
/** proxy agent uri or options, default is null. */
proxy?: string | { [key: string]: any };
/** DNS cache lookup interval */
dnsCacheLookupInterval?: number;
/** DNS cache max age */
dnsCacheMaxLength?: number;
}
export interface EggAppConfig {
workerStartTimeout: number;
baseDir: string;
middleware: string[];
/**
* The option of `bodyParser` middleware
*
* @member Config#bodyParser
* @property {Boolean} enable - enable bodyParser or not, default to true
* @property {String | RegExp | Function | Array} ignore - won't parse request body when url path hit ignore pattern, can not set `ignore` when `match` presented
* @property {String | RegExp | Function | Array} match - will parse request body only when url path hit match pattern
* @property {String} encoding - body encoding config, default utf8
* @property {String} formLimit - form body size limit, default 1mb
* @property {String} jsonLimit - json body size limit, default 1mb
* @property {String} textLimit - json body size limit, default 1mb
* @property {Boolean} strict - json body strict mode, if set strict value true, then only receive object and array json body
* @property {Number} queryString.arrayLimit - from item array length limit, default 100
* @property {Number} queryString.depth - json value deep length, default 5
* @property {Number} queryString.parameterLimit - paramter number limit ,default 1000
* @property {string[]} enableTypes - parser will only parse when request type hits enableTypes, default is ['json', 'form']
* @property {any} extendTypes - support extend types
*/
bodyParser: {
enable: boolean;
encoding: string;
formLimit: string;
jsonLimit: string;
textLimit: string;
strict: boolean;
queryString: {
arrayLimit: number;
depth: number;
parameterLimit: number;
};
ignore: IgnoreOrMatch;
match: IgnoreOrMatch;
enableTypes: string[];
extendTypes: {
json: string[];
form: string[];
text: string[];
};
};
/**
* logger options
* @member Config#logger
* @property {String} dir - directory of log files
* @property {String} encoding - log file encoding, defaults to utf8
* @property {String} level - default log level, could be: DEBUG, INFO, WARN, ERROR or NONE, defaults to INFO in production
* @property {String} consoleLevel - log level of stdout, defaults to INFO in local serverEnv, defaults to WARN in unittest, defaults to NONE else wise
* @property {Boolean} disableConsoleAfterReady - disable logger console after app ready. defaults to `false` on local and unittest env, others is `true`.
* @property {Boolean} outputJSON - log as JSON or not, defaults to false
* @property {Boolean} buffer - if enabled, flush logs to disk at a certain frequency to improve performance, defaults to true
* @property {String} errorLogName - file name of errorLogger
* @property {String} coreLogName - file name of coreLogger
* @property {String} agentLogName - file name of agent worker log
* @property {Object} coreLogger - custom config of coreLogger
* @property {Boolean} allowDebugAtProd - allow debug log at prod, defaults to true
*/
logger: EggLoggerConfig;
/** custom logger of egg */
customLogger: {
[key: string]: EggLoggerOptions;
};
/** Configuration of httpClient in egg. */
httpClient: HttpClientConfig;
development: {
/**
* dirs needed watch, when files under these change, application will reload, use relative path
*/
watchDirs: string[];
/**
* dirs don't need watch, including subdirectories, use relative path
*/
ignoreDirs: string[];
/**
* don't wait all plugins ready, default is true.
*/
fastReady: boolean;
/**
* whether reload on debug, default is true.
*/
reloadOnDebug: boolean;
/**
* whether override default watchDirs, default is false.
*/
overrideDefault: boolean;
/**
* whether to reload, use https://github.com/sindresorhus/multimatch
*/
reloadPattern: string[] | string;
};
/**
* customLoader config
*/
customLoader: {
[key: string]: CustomLoaderConfig;
};
/**
* It will ignore special keys when dumpConfig
*/
dump: {
ignore: Set<string>;
};
/**
* The environment of egg
*/
env: EggEnvType;
/**
* The current HOME directory
*/
HOME: string;
hostHeaders: string;
/**
* I18n options
*/
i18n: {
/**
* default value EN_US
*/
defaultLocale: string;
/**
* i18n resource file dir, not recommend to change default value
*/
dir: string;
/**
* custom the locale value field, default `query.locale`, you can modify this config, such as `query.lang`
*/
queryField: string;
/**
* The locale value key in the cookie, default is locale.
*/
cookieField: string;
/**
* Locale cookie expire time, default `1y`, If pass number value, the unit will be ms
*/
cookieMaxAge: string | number;
};
/**
* Detect request' ip from specified headers, not case-sensitive. Only worked when config.proxy set to true.
*/
ipHeaders: string;
/**
* jsonp options
* @member Config#jsonp
* @property {String} callback - jsonp callback method key, default to `_callback`
* @property {Number} limit - callback method name's max length, default to `50`
* @property {Boolean} csrf - enable csrf check or not. default to false
* @property {String|RegExp|Array} whiteList - referrer white list
*/
jsonp: {
limit: number;
callback: string;
csrf: boolean;
whiteList: string | RegExp | Array<string | RegExp>;
};
/**
* The key that signing cookies. It can contain multiple keys separated by .
*/
keys: string;
/**
* The name of the application
*/
name: string;
/**
* package.json
*/
pkg: any;
rundir: string;
security: {
domainWhiteList: string[];
protocolWhiteList: string[];
defaultMiddleware: string;
csrf: any;
xframe: {
enable: boolean;
value: 'SAMEORIGIN' | 'DENY' | 'ALLOW-FROM';
};
hsts: any;
methodnoallow: { enable: boolean };
noopen: { enable: boolean; }
xssProtection: any;
csp: any;
};
siteFile: PlainObject<string | Buffer>;
watcher: PlainObject;
onClientError(err: Error, socket: Socket, app: EggApplication): ClientErrorResponse | Promise<ClientErrorResponse>;
/**
* server timeout in milliseconds, default to 2 minutes.
*
* for special request, just use `ctx.req.setTimeout(ms)`
*
* @see https://nodejs.org/api/http.html#http_server_timeout
*/
serverTimeout: number | null;
[prop: string]: any;
}
export interface ClientErrorResponse {
body: string | Buffer;
status: number;
headers: { [key: string]: string };
}
export interface Router extends KoaRouter<any, Context> {
/**
* restful router api
*/
resources(name: string, prefix: string, ...middleware: any[]): Router;
/**
* @param {String} name - Router name
* @param {Object} params - more parameters
* @example
* ```js
* router.url('edit_post', { id: 1, name: 'foo', page: 2 })
* => /posts/1/edit?name=foo&page=2
* router.url('posts', { name: 'foo&1', page: 2 })
* => /posts?name=foo%261&page=2
* ```
* @return {String} url by path name and query params.
* @since 1.0.0
*/
url(name: string, params: any): any;
}
export interface EggApplication extends EggCoreBase<EggAppConfig> { // tslint:disable-line
/**
* HttpClient instance
*/
httpClient: EggHttpClient;
/**
* Logger for Application, wrapping app.coreLogger with context information
*
* @member {ContextLogger} Context#logger
* @since 1.0.0
* @example
* ```js
* this.logger.info('some request data: %j', this.request.body);
* this.logger.warn('WARNING!!!!');
* ```
*/
logger: EggLogger;
/**
* core logger for framework and plugins, log file is $HOME/logs/{appName}/egg-web
*/
coreLogger: EggLogger;
/**
* All loggers contain logger, coreLogger and customLogger
*/
loggers: EggLoggers;
/**
* messenger instance
*/
messenger: Messenger;
/**
* get router
*/
router: Router;
/**
* create a singleton instance
*/
addSingleton(name: string, create: any): void;
runSchedule(schedulePath: string): Promise<any>;
/**
* http request helper base on httpClient, it will auto save httpClient log.
* Keep the same api with httpClient.request(url, args).
* See https://github.com/node-modules/urllib#api-doc for more details.
*/
curl: EggHttpClient['request'];
/**
* Get logger by name, it's equal to app.loggers['name'], but you can extend it with your own logical
*/
getLogger(name: string): EggLogger;
/**
* print the information when console.log(app)
*/
inspect(): any;
/**
* Alias to Router#url
*/
url(name: string, params: any): any;
/**
* Create an anonymous context, the context isn't request level, so the request is mocked.
* then you can use context level API like `ctx.service`
* @member {String} EggApplication#createAnonymousContext
* @param {Request} req - if you want to mock request like querystring, you can pass an object to this function.
* @return {Context} context
*/
createAnonymousContext(req?: Request): Context;
/**
* export context base classes, let framework can impl sub class and over context extend easily.
*/
ContextCookies: typeof EggCookies;
ContextLogger: typeof EggContextLogger;
ContextHttpClient: EggContextHttpClientConstructor;
HttpClient: EggHttpConstructor;
Subscription: typeof Subscription;
Controller: typeof Controller;
Service: typeof Service;
/** lcj */
BaseController: typeof BaseController;
BaseService: typeof BaseService;
}
// compatible
export class EggApplication {
constructor(options?: CoreOptions);
}
export type RouterPath = string | RegExp;
export class Application extends EggApplication {
/**
* global locals for view
* @see Context#locals
*/
locals: IApplicationLocals;
/**
* HTTP get method
*/
get(path: RouterPath, fn: string): void;
get(path: RouterPath, ...middleware: any[]): void;
/**
* HTTP post method
*/
post(path: RouterPath, fn: string): void;
post(path: RouterPath, ...middleware: any[]): void;
/**
* HTTP put method
*/
put(path: RouterPath, fn: string): void;
put(path: RouterPath, ...middleware: any[]): void;
/**
* HTTP patch method
*/
patch(path: RouterPath, fn: string): void;
patch(path: RouterPath, ...middleware: any[]): void;
/**
* HTTP delete method
*/
delete(path: RouterPath, fn: string): void;
delete(path: RouterPath, ...middleware: any[]): void;
/**
* restful router api
*/
resources(name: string, prefix: string, fn: string): Router;
resources(path: string, prefix: string, ...middleware: any[]): Router;
redirect(path: string, redirectPath: string): void;
controller: IController;
middleware: KoaApplication.Middleware[] & IMiddleware;
/**
* Run async function in the background
* @see Context#runInBackground
* @param {Function} scope - the first args is an anonymous ctx
*/
runInBackground(scope: (ctx: Context) => void): void;
}
export interface IApplicationLocals extends PlainObject { }
export interface FileStream extends Readable { // tslint:disable-line
fields: any;
filename: string;
fieldname: string;
mime: string;
mimeType: string;
transferEncoding: string;
encoding: string;
truncated: boolean;
}
interface GetFileStreamOptions {
requireFile?: boolean; // required file submit, default is true
defCharset?: string;
limits?: {
fieldNameSize?: number;
fieldSize?: number;
fields?: number;
fileSize?: number;
files?: number;
parts?: number;
headerPairs?: number;
};
checkFile?(
fieldname: string,
file: any,
filename: string,
encoding: string,
mimetype: string
): void | Error;
}
/**
* KoaApplication's Context will carry the default 'cookie' property in
* the egg's Context interface, which is wrong here because we have our own
* special properties (e.g: encrypted). So we must remove this property and
* create our own with the same name.
* @see https://github.com/eggjs/egg/pull/2958
*
* However, the latest version of Koa has "[key: string]: any" on the
* context, and there well be a type error for "keyof koa.Context".
* So we have to directly inherit from "KoaApplication.BaseContext" and
* rewrite all the properties to be compatible with types in Koa.
* @see https://github.com/eggjs/egg/pull/3329
*/
export interface Context extends KoaApplication.BaseContext {
[key: string]: any;
app: Application;
// properties of koa.Context
req: IncomingMessage;
res: ServerResponse;
originalUrl: string;
respond?: boolean;
service: IService;
request: Request;
response: Response;
// The new 'cookies' instead of Koa's.
cookies: EggCookies;
helper: IHelper;
/**
* Resource Parameters
* @example
* ##### ctx.params.id {string}
*
* `GET /api/users/1` => `'1'`
*
* ##### ctx.params.ids {Array<String>}
*
* `GET /api/users/1,2,3` => `['1', '2', '3']`
*
* ##### ctx.params.fields {Array<String>}
*
* Expect request return data fields, for example
* `GET /api/users/1?fields=name,title` => `['name', 'title']`.
*
* ##### ctx.params.data {Object}
*
* Tht request data object
*
* ##### ctx.params.page {Number}
*
* Page number, `GET /api/users?page=10` => `10`
*
* ##### ctx.params.per_page {Number}
*
* The number of every page, `GET /api/users?per_page=20` => `20`
*/
params: any;
/**
* @see Request#accept
*/
queries: PlainObject<string[]>;
/**
* @see Request#accept
*/
accept: accepts.Accepts;
/**
* @see Request#acceptJSON
*/
acceptJSON: boolean;
/**
* @see Request#ip
*/
ip: string;
/**
* @see Response#realStatus
*/
realStatus: number;
/**
* Set the ctx.body.data value
*
* @member {Object} Context#data=
* @example
* ```js
* ctx.data = {
* id: 1,
* name: 'fol'
* };
* ```
*
* will get response
*
* ```js
* HTTP/1.1 200 OK
*
* {
* "data": {
* "id": 1,
* "name": "fol"
* }
* }
* ```
*/
data: any;
/**
* set ctx.body.meta value
*
* @example
* ```js
* ctx.meta = {
* count: 100
* };
* ```
* will get response
*
* ```js
* HTTP/1.1 200 OK
*
* {
* "meta": {
* "count": 100
* }
* }
* ```
*/
meta: any;
/**
* locals is an object for view, you can use `app.locals` and `ctx.locals` to set variables,
* which will be used as data when view is rendering.
* The difference between `app.locals` and `ctx.locals` is the context level, `app.locals` is global level, and `ctx.locals` is request level. when you get `ctx.locals`, it will merge `app.locals`.
*
* when you set locals, only object is available
*
* ```js
* this.locals = {
* a: 1
* };
* this.locals = {
* b: 1
* };
* this.locals.c = 1;
* console.log(this.locals);
* {
* a: 1,
* b: 1,
* c: 1,
* };
* ```
*
* `ctx.locals` has cache, it only merges `app.locals` once in one request.
*
* @member {Object} Context#locals
*/
locals: IApplicationLocals & IContextLocals;
/**
* alias to {@link locals}, compatible with koa that use this variable
*/
state: any;
/**
* Logger for Application, wrapping app.coreLogger with context information
*
* @member {ContextLogger} Context#logger
* @since 1.0.0
* @example
* ```js
* this.logger.info('some request data: %j', this.request.body);
* this.logger.warn('WARNING!!!!');
* ```
*/
logger: EggLogger;
/**
* Get logger by name, it's equal to app.loggers['name'], but you can extend it with your own logical
*/
getLogger(name: string): EggLogger;
/**
* Request start time
*/
starttime: number;
/**
* http request helper base on httpClient, it will auto save httpClient log.
* Keep the same api with httpClient.request(url, args).
* See https://github.com/node-modules/urllib#api-doc for more details.
*/
curl: EggHttpClient['request'];
__(key: string, ...values: string[]): string;
gettext(key: string, ...values: string[]): string;
/**
* get upload file stream
* @example
* ```js
* const stream = await this.getFileStream();
* // get other fields
* console.log(stream.fields);
* ```
* @method Context#getFileStream
* @param {Object} options
* @return {ReadStream} stream
* @since 1.0.0
*/
getFileStream(options?: GetFileStreamOptions): Promise<FileStream>;
/**
* @see Response.redirect
*/
redirect(url: string, alt?: string): void;
httpClient: EggContextHttpClient;
}
export interface IContextLocals extends PlainObject { }
export class Controller extends BaseContextClass { }
export class Service extends BaseContextClass { }
export class Subscription extends BaseContextClass { }
/** egg-orm-ts */
export class BaseController extends Controller {
/**
* 统一公共调用方法
* @param {object} params 参数
* @param {object} paramsSchema 参数校验Joi对象
* @param {string} methodName 方法名称
* @param {object} resultSchema 结果校验Joi对象
* @return {object} result 原始dao响应对象
*/
protected callService(params?: any, paramsSchema?: AnySchema, methodName?: string, resultSchema?: AnySchema): any;
/**
* 默认 统一处理响应结果(可自定义)
* - 接口会自动过滤掉 undefined 的属性,则转换为 null
* @param res 参数
*/
protected success(res: any): any;
}
export class BaseService<Entity extends ObjectLiteral> extends Service {
/**
* Repository of this model.
*/
modelName: string;
model: Repository<Entity>;
/**
* Repository of this connection.
* @see https://github.com/typeorm/typeorm#using-repositories
*/
repo: { [key: string]: Repository<any> };
OPR:{ [key: string]: any };
FIND_OPTIONS_KEYS: string[];
/**
* Common error info.
*/
HTTP_CODE: {[key in HTTP_CODE]: number};
BIZ_CODE: {[key in BIZ_CODE]: number};
BizError: (message: string, code?: number) => any;
/**
* Utils API
*/
/**
* 唯一性校验
* - 必须使用 await 调用
* - 支持排除当前 id
* - 至少一个属性不为空才判断重复
* @param params 校验参数对象
* @param message 提示信息(不传则使用默认值)
*/
protected checkUnique(params: FindConditions<Entity> | ObjectLiteral | AdvanceCondition, message: string): void;
/**
* Executes raw SQL query and returns raw database results
*/
protected query(sql: string, params?: any[], runner?: QueryRunner): Promise<any>;
/**
* Base API
* - Default api, should overwrite if need.
* - Others use repo, model or manager to implement.
*/
// protected save<T extends DeepPartial<Entity>>(entity: T, options?: SaveOptions): Promise<T & Entity & SuccessFlag>;
protected save<T extends DeepPartial<Entity>>(entity: T, options?: SaveOptions): Promise<{
success: boolean;
data: T & Entity & SuccessFlag;
}>;;
protected get(id: string | number | Date | ObjectID, options?: FindOneOptions<Entity>): Promise<Entity>;
protected getOne(conditions?: FindConditions<Entity> | ObjectLiteral | AdvanceCondition, options?: FindOneOptions<Entity>): Promise<Entity>;
protected getListByIds(ids: any[], options?: FindConditions<Entity> | FindManyOptions<Entity> | ObjectLiteral): Promise<Entity[]>;
/**
* Find with pagination and condition.
*/
protected getPage(params?: PageParam & ListParam<Entity>, dataFunc?: (arg: Entity[]) => void): Promise<PageProps<Entity>>;
/**
* Update with id only (not use criteria).
* @param params param
* @param params.id primary key
* @param params.partialEntity new data
*/
protected updateMix(params: DeepPartial<Entity> | any): Promise<UpdateResult & SuccessFlag>;
protected update(criteria: CriteriaParam<Entity>, partialEntity: DeepPartial<Entity>): Promise<UpdateResult & SuccessFlag>;
protected delete(criteria: CriteriaParam<Entity>): Promise<DeleteResult & SuccessFlag>;
// protected saveList<T extends DeepPartial<Entity>>(entities: T[], options?: SaveOptions): Promise<(T & Entity & SuccessFlag)[]>;
protected saveList<T extends DeepPartial<Entity>>(entities: T[], options?: SaveOptions): Promise<{
success: boolean;
data: (T & Entity & SuccessFlag)[];
}>;
/**
* 查询列表
* @param params 参数
* @param dataFunc 数据处理函数
* @returns
*/
protected getList(conditions?: ListParam<Entity>, dataFunc?: (arg: Entity[]) => void): Promise<Entity[]>;
/**
* Update with ids only (not use criteria).
* @param params param
* @param params.id primary key
* @param params.partialEntity new data
*/
protected updateListMix(params: {ids: any[]} & (DeepPartial<Entity> | any)): Promise<UpdateResult & SuccessFlag>;
protected updateList(criteria: CriteriaParam<Entity>, partialEntity: DeepPartial<Entity>): Promise<UpdateResult & SuccessFlag>;
protected deleteList(criteria: CriteriaParam<Entity>): Promise<DeleteResult & SuccessFlag>;
/**
* Utils function.
*/
/**
* 转换 Find*Options
* @param params 查询条件
* @returns
*/
protected getOptions(params: any): any;
/**
* 转换条件
* @param params 查询条件
* @returns
*/
protected getWhere(params: any): any;
/**
* 转换排序条件
* - 合并 order 和 sort(AntD 默认)参数
* @param params
* @returns
*/
protected getOrders(params: any): any;
// 合并参数
protected combineParams(first: any, second: any): any;
/**
* deal mix params
* @param params 参数
*/
protected getAndDelete(params: any, label: string, defaultValue?: any): any;
}
/**
* 工具类
*/
/**
* ErrorUtils
*/
export const HTTP_CODE: {[key in HTTP_CODE]: number};
export const HTTP_CODE_MESSAGE: HTTP_CODE_MESSAGE;
export const BIZ_CODE: {[key in BIZ_CODE]: number};
export class BaseError {
protected code: number;
protected name: string;
protected timestamp: number;
constructor(message: string, code?: number);
}
export class BizError extends BaseError {
constructor(message: string, code: number);
}
/**
* ObjectUtils
*/
export type Batch = (_obj: any, _fn: any) => any;
export const batch: Batch;
export const modifyValues: (_obj: any, _fn: (arg0: any) => any) => any;
/**
* 判断空对象
* - null 或者 {}
* - 没有一个合法属性(allFlag: false/undefined) 或 有一个非法属性(allFlag: true)
* @param obj 参数
* @param allFlag 判断属性标志
* @returns boolean
*/
export const isEmptyObject: (obj: any, allFlag?: boolean) => boolean;
/**
* 判断空数组
* - null, undefined 或者 空数组,
* - 数据元素全部为非法;
* @param arr 数组对象
* @returns boolean
*/
export const isEmptyArray: (arr: any) => boolean;
/**
* 对象数组 转 指定属性的值的数组
* @param arrayList 对象数组 [{}]
* @param key 对象属性
* @returns array
*/
export const getValuesByKey: (arrayList: any[], key: string) => any[];
/**
* 对象数组 转 指定属性的值的 map
* @param arrayList 对象数组 [{}]
* @param key 对象属性
* @returns object
*/
export const getMapByKey: (arrayList: any[], key: string | number) => object;
/**
* 转换list[{parent_[attr], [attr]}] 为 树结构数据
* @param dataList 边表节点数组
* @param rootAttrValue 根节点(如果未指定则返回分类列表)
* @param attr 属性值,默认 id
* @returns any
*/
export const convertListToTree: (dataList: any[], rootAttrValue: string | number, attr?: string) => any;
/**
* StringUtils
*/
export const getModelName: (file: string) => string;
export const formatPaths: (files: string[]) => {
name: string;
importPath: string;
};
export const formatCode: (text: string) => any;
/**
* 大/小驼峰式转下划线
* @param str 字符串参数
*/
export const underlineCase: (str: string) => string;
/**
* 首字母转小写
* @param str 字符串参数
*/
export const lowerFirst: (str: string) => string;
/**
* 首字母转大写
* @param str 字符串参数
*/
export const upperFirst: (str: string) => string;
/**
* 小驼峰式
* @param str 字符串参数
*/
export const lowerCamelize: (str: string) => string;
/**
* 大驼峰式(即帕斯卡命名法)
* @param str 字符串参数
*/
export const upperCamelize: (str: string) => string;
/**
* 随机字符串
* - 默认大小写字母和数字
* @param len 长度 默认32
* @param extraChr 额外字符串
* @returns string
*/
export const getRandomStr: (len?: number, extraChr?: string) => string;
/**
* 替换指定字符串为等长相同字符
* - 默认用 ’*‘ 替换
* @param str 被替换字符串
* @param replaceChar 替换字符,default '*'
* @returns
*/
export const generateChars:(str: string, replaceChar?: string) => string;
/**
* 脱敏字符串
* - 至少脱敏1位
* - charFunc 支持扩展替换规则
* @param str 字符串
* @param start 开始位数,default 1
* @param end 结束位数,default 1
* @param charFunc 脱敏函数,默认用 @function generateChars
* @returns 脱敏后字符串
**/
export const desensitize: (str: string, start?: number, end?: number, charFunc?: (str: string) => string) => string;
/**
* 左补齐
* @param val 原值,默认为 ''
* @param len 位数,默认 1
* @param chr 补位字符,默认‘0’
* @returns string
*/
export const padStart: (val: any, len: number, chr?: string) => string;
/**
* 判断合法值(非空)
* - 非 null, undefined, '', NaN, 0
* @param val 参数
* @returns boolean
*/
export const isValid: (val: any) => boolean;
/**
* 获取合法值
* @param val 参数
* @param defaultValue 指定默认值
* @returns any
*/
export const getValid: (val: any, defaultValue: any) => any;
/**
* 判断数据类型
* @param val 参数
* @param type 判断类型
* @returns boolean
*/
export const isType: (val: any, type: DATA_TYPE) => boolean;
/**
* 获取文件类型
* - 图片(image), 语音(voice), 视频(video), 普通文件(file)
* - 钉钉/企业微信接口使用
* @param fileName 文件名称
* @returns fileType
*/
export const getFileType: (fileName: string) => string;
/**
* The empty interface `IService` is a placeholder, for egg
* to auto injection service to ctx.service
*
* @example
*
* import { Service } from 'egg';
* class FooService extends Service {
* async bar() {}
* }
*
* declare module 'egg' {
* export interface IService {
* foo: FooService;
* }
* }
*
* Now I can get ctx.service.foo at controller and other service file.
*/
export interface IService extends PlainObject { } // tslint:disable-line
export interface IController extends PlainObject { } // tslint:disable-line
export interface IDao extends PlainObject { } // tslint:disable-line
export interface IMiddleware extends PlainObject { } // tslint:disable-line
export interface IHelper extends PlainObject, BaseContextClass {
/**
* Generate URL path(without host) for route. Takes the route name and a map of named params.
* @method Helper#pathFor
* @param {String} name - Router Name
* @param {Object} params - Other params
*
* @example
* ```js
* app.get('home', '/index.htm', 'home.index');
* ctx.helper.pathFor('home', { by: 'recent', limit: 20 })
* => /index.htm?by=recent&limit=20
* ```
* @return {String} url path(without host)
*/
pathFor(name: string, params?: PlainObject): string;
/**
* Generate full URL(with host) for route. Takes the route name and a map of named params.
* @method Helper#urlFor
* @param {String} name - Router name
* @param {Object} params - Other params
* @example
* ```js
* app.get('home', '/index.htm', 'home.index');
* ctx.helper.urlFor('home', { by: 'recent', limit: 20 })
* => http://127.0.0.1:7001/index.htm?by=recent&limit=20
* ```
* @return {String} full url(with host)
*/
urlFor(name: string, params?: PlainObject): string;
}
// egg env type
export type EggEnvType = 'local' | 'unittest' | 'prod' | string;
/**
* plugin config item interface
*/
export interface IEggPluginItem {
env?: EggEnvType[];
path?: string;
package?: string;
enable?: boolean;
}
export type EggPluginItem = IEggPluginItem | boolean;
/**
* build-in plugin list
*/
export interface EggPlugin {
[key: string]: EggPluginItem | undefined;
onerror?: EggPluginItem;
session?: EggPluginItem;
i18n?: EggPluginItem;
watcher?: EggPluginItem;
multipart?: EggPluginItem;
security?: EggPluginItem;
development?: EggPluginItem;
logrotator?: EggPluginItem;
schedule?: EggPluginItem;
static?: EggPluginItem;
jsonp?: EggPluginItem;
view?: EggPluginItem;
}
/**
* Singleton instance in Agent Worker, extend {@link EggApplication}
*/
export class Agent extends EggApplication {
}
export interface ClusterOptions {
/** specify framework that can be absolute path or npm package */
framework?: string;
/** directory of application, default to `process.cwd()` */
baseDir?: string;
/** customized plugins, for unittest */
plugins?: object | null;
/** numbers of app workers, default to `os.cpus().length` */
workers?: number;
/** listening port, default to 7001(http) or 8443(https) */
port?: number;
/** https or not */
https?: boolean;
/** ssl key */
key?: string;
/** ssl cert */
cert?: string;
[prop: string]: any;
}
export function startCluster(options: ClusterOptions, callback: (...args: any[]) => any): void;
export interface StartOptions{
/** specify framework that can be absolute path or npm package */
framework?: string;
/** directory of application, default to `process.cwd()` */
baseDir?: string;
/** ignore single process mode warning */
ignoreWarning? :boolean;
}
export function start(options?:StartOptions):Promise<Application>
/**
* Powerful Partial, Support adding ? modifier to a mapped property in deep level
* @example
* import { PowerPartial, EggAppConfig } from 'egg';
*
* // { view: { defaultEngines: string } } => { view?: { defaultEngines?: string } }
* type EggConfig = PowerPartial<EggAppConfig>
*/
export type PowerPartial<T> = {
[U in keyof T]?: T[U] extends object
? PowerPartial<T[U]>
: T[U]
};
// send data can be number|string|boolean|object but not Set|Map
export interface Messenger extends EventEmitter {
/**
* broadcast to all agent/app processes including itself
*/
broadcast(action: string, data: any): void;
/**
* send to agent from the app,
* send to an random app from the agent
*/
sendRandom(action: string, data: any): void;
/**
* send to specified process
*/
sendTo(pid: number, action: string, data: any): void;
/**
* send to agent from the app,
* send to itself from the agent
*/
sendToAgent(action: string, data: any): void;
/**
* send to all app including itself from the app,
* send to all app from the agent
*/
sendToApp(action: string, data: any): void;
}
// compatible
export interface EggLoaderOptions extends CoreLoaderOptions {}
export interface EggLoader extends CoreLoader {}
/**
* App worker process Loader, will load plugins
* @see https://github.com/eggjs/egg-core
*/
export class AppWorkerLoader extends CoreLoader {
loadConfig(): void;
load(): void;
}
/**
* Agent worker process loader
* @see https://github.com/eggjs/egg-loader
*/
export class AgentWorkerLoader extends CoreLoader {
loadConfig(): void;
load(): void;
}
export interface IBoot {
/**
* Ready to call configDidLoad,
* Config, plugin files are referred,
* this is the last chance to modify the config.
*/
configWillLoad?(): void;
/**
* Config, plugin files have loaded
*/
configDidLoad?(): void;
/**
* All files have loaded, start plugin here
*/
didLoad?(): Promise<void>;
/**
* All plugins have started, can do some thing before app ready
*/
willReady?(): Promise<void>;
/**
* Worker is ready, can do some things,
* don't need to block the app boot
*/
didReady?(): Promise<void>;
/**
* Server is listening
*/
serverDidReady?(): Promise<void>;
/**
* Do some thing before app close
*/
beforeClose?(): Promise<void>;
}
export interface Singleton<T> {
get(id: string): T;
}
/**
* egg-multipart
*/
interface EggFile {
field: string;
filename: string;
encoding: string;
mime: string;
filepath: string;
}
interface MultipartOptions {
requireFile?: boolean; // required file submit, default is true
defCharset?: string;
limits?: {
fieldNameSize?: number;
fieldSize?: number;
fields?: number;
fileSize?: number;
files?: number;
parts?: number;
headerPairs?: number;
};
checkFile?(
fieldname: string,
file: any,
filename: string,
encoding: string,
mimetype: string
): void | Error;
}
interface MultipartFileStream extends Readable {
fields: any;
filename: string;
fieldname: string;
mime: string;
mimeType: string;
transferEncoding: string;
encoding: string;
truncated: boolean;
}
interface ScheduleOptions {
type?: string;
cron?: string;
cronOptions?: {
tz?: string;
utc?: boolean;
iterator?: boolean;
currentDate?: string|number|Date;
endDate?: string|number|Date;
};
interval?: number|string;
immediate?: boolean;
disable?: boolean;
env?: string[];
}
// egg
interface Context {
/**
* clean up request tmp files helper
* @param {EggFile[]} files file paths need to clenup, default is `ctx.request.files`.
* @return {Promise<void>}
*/
cleanupRequestFiles(files?: EggFile[]): Promise<void>;
/**
* save request multipart data and files to `ctx.request`
* @return {Promise<void>}
*/
saveRequestFiles(): Promise<void>;
/**
* create multipart.parts instance, to get separated files.
* @param {MultipartOptions} options
* @return {Function} return a function which return a Promise
*/
multipart(options?: MultipartOptions): (fn?: Function) => Promise<any>;
/**
* get upload file stream
* @param {MultipartOptions} options
* @return {Promise<MultipartFileStream>}
*/
getFileStream(options?: MultipartOptions): Promise<MultipartFileStream>
}
interface Request {
/**
* Files Object Array
*/
files: EggFile[];
}
type MatchItem = string | RegExp | ((ctx: Context) => boolean);
interface EggAppConfig {
multipart: {
mode?: string;
fileModeMatch?: MatchItem | MatchItem[];
autoFields?: boolean;
defaultCharset?: string;
fieldNameSize?: number;
fieldSize?: string|number;
fields?: number;
fileSize?: string|number;
files?: number;
whitelist?: ((filename: string) => boolean)|string[];
fileExtensions?: string[];
tmpdir?: string;
cleanSchedule?: ScheduleOptions;
}
}
}