some more code splitting

This commit is contained in:
TopchetoEU 2023-06-26 17:16:44 +03:00
parent f7ff1605e1
commit d6bfd50173
No known key found for this signature in database
GPG Key ID: 24E57B2E9C61AD19
5 changed files with 81 additions and 72 deletions

View File

@ -1,8 +1,7 @@
import { Collection } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
import HttpError from "../server/HttpError.ts";
import User from "../models/User.ts";
import { rest } from "../server/Router.ts";
import { body, schema } from "../server/decorators.ts";
import { body, rest, schema } from "../server/decorators.ts";
import AppRouter from "./AppRouter.ts";
import * as bcrypt from "https://deno.land/x/bcrypt@v0.4.1/mod.ts";

View File

@ -1,4 +1,3 @@
// deno-lint-ignore-file no-explicit-any ban-types
import { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts";
import serialize from "./serialize.ts";
import HttpError from "./HttpError.ts";
@ -7,8 +6,6 @@ import RestRequest from "./RestRequest.ts";
export type HandlerRes = Promise<RestResponse | undefined> | RestResponse | undefined;
export type HttpMethod = '*' | 'GET' | 'POST' | 'CHANGE' | 'DELETE' | 'PUT' | 'UPDATE';
export interface Handler {
handle(req: RestRequest): HandlerRes;
}
@ -16,13 +13,18 @@ export interface RestOptions {
route?: string;
}
type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise<unknown> | unknown;
type Base<KeyT extends string> = Router & { [X in KeyT]: Function; };
export type ProcessFunc = (req: RestRequest, arg: unknown, name: string) => Promise<unknown> | unknown;
interface RouterHandler {
export interface RouterHandler {
path: string;
handler: Handler;
}
export function addMetaQuery<T extends Router>(target: T, ...handlers: ((r: T) => RouterHandler)[]) {
let props = Reflect.getOwnMetadata('router:queries', target);
if (props === undefined) Reflect.defineMetadata('router:queries', props = [], target);
props.push(...handlers);
}
export function makeParameterModifier(func: ProcessFunc) {
return (target: Router, key: string, index: number) => {
@ -36,69 +38,6 @@ export function makeParameterModifier(func: ProcessFunc) {
}
function addMetaQuery(target: any, ...handlers: ((r: Router) => RouterHandler)[]) {
let props = Reflect.getOwnMetadata('router:queries', target);
if (props === undefined) Reflect.defineMetadata('router:queries', props = [], target);
props.push(...handlers);
}
export function rest<KeyT extends keyof T & string, T extends Base<KeyT>>(method: HttpMethod, route?: string) {
return (target: T, key: KeyT) => {
const path = route ?? key;
addMetaQuery(target, (r: any) => ({
path, handler: {
async handle(req) {
if (method !== '*' && req.method.toUpperCase() !== method) return undefined;
const params: string[] = [];
const func = (r as T)[key];
const args: any[] = [];
const allMods: ([ProcessFunc, ...ProcessFunc[]] | undefined)[] = [];
let signature = (target[key] as Function).toString();
signature = signature.substring(signature.indexOf('(') + 1, signature.indexOf(')'));
params.push(...signature.split(',').map(v => v.trim()).filter(v => v !== ''));
for (let proto = target; proto instanceof Router; proto = Object.getPrototypeOf(proto)) {
const data = Reflect.getOwnMetadata('router:params', proto, key);
if (!data) continue;
for (let i = 0; i < data.length; i++) {
allMods[i] ??= [] as any;
if (data[i]) allMods[i]!.push(...data[i]);
}
}
for (let i = 0; i < params.length; i++) {
const param = params[i];
let arg: any = req.params[param];
for (const mod of allMods[i] ?? []) {
arg = await mod(req, arg, params[i]);
}
args.push(arg);
}
const res = func.apply(r, args);
if (res instanceof RestResponse) return res;
return new RestResponse().body(await serialize(res));
}
},
}));
};
}
export function route<KeyT extends keyof T & string, T extends Router & { [x in KeyT]: Handler }>(path?: string) {
return (target: T, key: KeyT) => {
addMetaQuery(target, (r: any) => ({
handler: r[key],
path: path ?? key,
}));
};
}
export default class Router {
private _handlers?: RouterHandler[];
public defaultHandler?: Handler;

View File

@ -1,5 +1,6 @@
import { rest, route } from "./Router.ts";
import body from "./decorators/body.ts";
import rest from "./decorators/rest.ts";
import route from "./decorators/route.ts";
import schema from "./decorators/schema.ts";
export { body, schema, rest, route };

View File

@ -0,0 +1,60 @@
// deno-lint-ignore-file ban-types
import { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts";
import RestResponse from "../RestResponse.ts";
import Router, { ProcessFunc, addMetaQuery } from "../Router.ts";
import serialize from "../serialize.ts";
export type HttpMethod = '*' | 'GET' | 'POST' | 'CHANGE' | 'DELETE' | 'PUT' | 'UPDATE';
type Base<KeyT extends string> = Router & { [X in KeyT]: Function; };
type ModArray = ([ProcessFunc, ...ProcessFunc[]] | undefined)[];
export default function rest<KeyT extends keyof T & string, T extends Base<KeyT>>(method: HttpMethod, route?: string) {
return (target: T, key: KeyT) => {
const path = route ?? key;
addMetaQuery(target, (r) => ({
path, handler: {
async handle(req) {
if (method !== '*' && req.method.toUpperCase() !== method) return undefined;
const params: string[] = [];
const args: unknown[] = [];
const allMods: ModArray = [];
let signature = r[key].toString();
signature = signature.substring(signature.indexOf('(') + 1, signature.indexOf(')'));
params.push(...signature.split(',').map(v => v.trim()).filter(v => v !== ''));
for (let proto = r; proto instanceof Router; proto = Object.getPrototypeOf(proto)) {
const data = Reflect.getOwnMetadata('router:params', proto, key) as ModArray;
if (!data) continue;
for (let i = 0; i < data.length; i++) {
if (data[i] === undefined) continue;
if (allMods[i]) allMods[i]!.push(...data[i]!);
else allMods[i] ??= [...data[i]!];
}
}
for (let i = 0; i < params.length; i++) {
const param = params[i];
let arg: unknown = req.params[param];
for (const mod of allMods[i] ?? []) {
arg = await mod(req, arg, params[i]);
}
args.push(arg);
}
const res = r[key].apply(r, args);
if (res instanceof RestResponse) return res;
return new RestResponse().body(await serialize(res));
}
},
}));
};
}

View File

@ -0,0 +1,10 @@
import Router, { Handler, addMetaQuery } from "../Router.ts";
export default function route<KeyT extends keyof T & string, T extends Router & { [x in KeyT]: Handler }>(path?: string) {
return (target: T, key: KeyT) => {
addMetaQuery(target, r => ({
handler: r[key],
path: path ?? key,
}));
};
}