UNPKG

@nodeswork/sbase

Version:

Basic REST api foundation from Nodeswork.

268 lines (266 loc) 8.17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); require("reflect-metadata"); const _ = require("underscore"); const declarations_1 = require("./declarations"); const overrides_1 = require("./overrides"); const params_1 = require("./params"); const utils_1 = require("./utils"); const koa_config_1 = require("./koa-config"); function Config(options) { return (cls) => { const meta = Reflect.getMetadata(declarations_1.METADATA_KEY, cls) || { middlewares: [], handlers: {}, routerOptions: {}, }; _.extend(meta.routerOptions, options); Reflect.defineMetadata(declarations_1.METADATA_KEY, meta, cls); }; } exports.Config = Config; function Handler(options = {}) { return (target, propertyKey) => { const cls = target.constructor; const meta = Reflect.getMetadata(declarations_1.METADATA_KEY, cls) || { middlewares: [], handlers: {}, routerOptions: {}, }; if (meta.handlers[propertyKey] == null) { meta.handlers[propertyKey] = { method: declarations_1.Method.GET, path: '/', middleware: null, }; } const m = meta.handlers[propertyKey]; if (options.middleware) { const middleware = _.isArray(options.middleware) ? utils_1.compose(options.middleware) : options.middleware; m.middleware = m.middleware == null ? middleware : utils_1.compose([middleware, m.middleware]); } if (options.method) { m.method = options.method; } if (options.path) { m.path = options.path; } if (options.name) { m.name = options.name; } if (m.path == null) { m.path = '/'; } Reflect.defineMetadata(declarations_1.METADATA_KEY, meta, cls); }; } exports.Handler = Handler; function Get(path, options = {}) { return Handler(_.extend({}, options, { path, method: declarations_1.Method.GET, })); } exports.Get = Get; function Post(path, options = {}) { return Handler(_.extend({}, options, { path, method: declarations_1.Method.POST, })); } exports.Post = Post; function Put(path, options = {}) { return Handler(_.extend({}, options, { path, method: declarations_1.Method.PUT, })); } exports.Put = Put; function Delete(path, options = {}) { return Handler(_.extend({}, options, { path, method: declarations_1.Method.DELETE, })); } exports.Delete = Delete; function Middleware(middlewares) { middlewares = _.chain([middlewares]) .flatten() .map(koa_config_1.sbaseKoaConfig.middlewareMapper) .value(); return (target, propertyKey, descriptor) => { if (propertyKey == null) { buildConstructorMiddleware(target, middlewares); } else { buildPropertyMiddleware(target, propertyKey, middlewares, descriptor); } }; } exports.Middleware = Middleware; /** * A IF middleware that helps a branch checking. Usage: * * @If(predictor, ifClause) * - execute ifClause when predictor returns true. * - execute next middleware when predictor returns false. * * @If(predictor, ifClause, elseClause) * - execute ifClause when predictor returns true. * - execute elseClause when predictor returns false. * * @param predictor - Predict which clause to execute. * @param ifClause - Execute when predictor returns true. * @param elseClause - Execute when predictor returns false. By default, execute * else clause. */ function If(predictor, ifClause, elseClause) { return Middleware(async (ctx, next) => { const value = predictor(ctx); const boolValue = utils_1.isPromise(value) ? await value : value; if (boolValue) { await ifClause(ctx, next); } else if (elseClause) { await elseClause(ctx, next); } else { await next(); } }); } exports.If = If; /** * A WHEN middleware that helps a branch checking, next middleware will always * be executed regardless what predictor returns. * * @param predictor - Predict when the when clause will be executed. * @param whenClause - Execute when predictor returns true. */ function When(predictor, whenClause) { return Middleware(async (ctx, next) => { const value = predictor(ctx); const boolValue = utils_1.isPromise(value) ? await value : value; if (boolValue && whenClause) { await whenClause(ctx, () => Promise.resolve({})); } await next(); }); } exports.When = When; /** * A CHECK middleware that helps determines if to execute next middleware. * Usage: * * @Check((ctx: Router.IRouterContext) => ctx.isAuthenticated()) * * @param predictor - Returns true to execute next middleware. */ function Check(predictor) { return Middleware(async (ctx, next) => { const value = predictor(ctx); const boolValue = utils_1.isPromise(value) ? await value : value; if (boolValue) { await next(); } }); } exports.Check = Check; /** * A Tee middleware that helps execute a side function. * Usage: * * @Tee((ctx: Router.IRouterContext) => console.log(ctx.path)) * * @param fn - The side function to execute. * @param opts.post - specifies run tee after returned. */ function Tee(fn, opts = {}) { async function process(ctx) { const value = fn(ctx, () => { }); if (utils_1.isPromise(value)) { await value; } } return Middleware(async (ctx, next) => { if (!opts.post) { await process(ctx); } await next(); if (opts.post) { await process(ctx); } }); } exports.Tee = Tee; function buildConstructorMiddleware(cls, middlewares) { const meta = _.clone(Reflect.getMetadata(declarations_1.METADATA_KEY, cls) || { middlewares: [], handlers: {}, routerOptions: {}, }); meta.middlewares = _.union(middlewares, meta.middlewares); Reflect.defineMetadata(declarations_1.METADATA_KEY, meta, cls); } function buildPropertyMiddleware(target, propertyKey, middlewares, descriptor) { const cls = target.constructor; const meta = _.clone(Reflect.getMetadata(declarations_1.METADATA_KEY, cls) || { middlewares: [], handlers: {}, routerOptions: {}, }); if (meta.handlers[propertyKey] == null) { meta.handlers[propertyKey] = { method: declarations_1.Method.GET, path: null, middleware: null, }; } if (descriptor != null) { descriptor.value = utils_1.compose(middlewares.concat(descriptor.value)); } else { const m = meta.handlers[propertyKey]; if (m.middleware == null) { m.middleware = utils_1.compose(middlewares); } else { m.middleware = utils_1.compose(middlewares.concat(m.middleware)); } } Reflect.defineMetadata(declarations_1.METADATA_KEY, meta, cls); } /** * Generate an overrides middleware to help build mongoose queries. * * 1. Fetch query params to override query: * @Overrides('request.query.status->query.status') * @Overrides('request.body.status->query.status') * * 2. Set object to override query: * @Overrides(['constValue', 'query.status']) * * 3. Extract object from ctx: * @Overrides([(ctx) => * moment(ctx.request.query.date).startOf('month').toDate(), * 'query.date', * ]) */ exports.Overrides = (...rules) => { return Middleware(overrides_1.overrides(...rules)); }; /** * Clear existing overrides. * * @ClearOverrides() */ exports.ClearOverrides = () => { return Middleware(overrides_1.clearOverrides()); }; exports.Params = (options) => { return Middleware(params_1.params(options)); }; //# sourceMappingURL=decorators.js.map