diff --git a/src/acts/setAct.ts b/src/acts/setAct.ts index 6bad9690..2ddfc01d 100644 --- a/src/acts/setAct.ts +++ b/src/acts/setAct.ts @@ -13,7 +13,7 @@ import { ActInp, Services } from "./types.ts"; export const setAct = ( acts: Services, - { type, schema, actName, validator, fn }: ActInp, + { type, schema, actName, validator, fn, preAct }: ActInp, ) => { if (!acts.main[type]) { throw new Error(`Invalid type: ${type}`); @@ -25,5 +25,6 @@ export const setAct = ( acts.main[type][schema][actName] = { validator, fn, + preAct, }; }; diff --git a/src/acts/types.ts b/src/acts/types.ts index d6715645..599d0d7b 100644 --- a/src/acts/types.ts +++ b/src/acts/types.ts @@ -22,8 +22,9 @@ export type ActFn = (body: Body) => any; * @interface */ export interface Act { - validator: Struct; - fn: ActFn; + validator: Struct; + fn: ActFn; + preAct?: Function[]; } /** * Acts include tow features : dynamic and static @@ -72,16 +73,16 @@ export interface Act { * }, */ export interface Acts { - dynamic: { - [key: string]: { - [key: string]: Act; - }; + dynamic: { + [key: string]: { + [key: string]: Act; }; - static: { - [key: string]: { - [key: string]: Act; - }; + }; + static: { + [key: string]: { + [key: string]: Act; }; + }; } /** @@ -131,8 +132,8 @@ export interface Acts { * if type of string we get answer of req with http Request , but if type of it equal to Acts with anwer to req directly */ export interface Services { - main: Acts; - [key: string]: Acts | string | undefined; + main: Acts; + [key: string]: Acts | string | undefined; } /** @@ -141,27 +142,32 @@ export interface Services { * @interface */ export interface ActInp { - /** - * type of action static or dynamic - * when equal to static for get static file (isdb) - * else for dynamic request(request to db ideed) - */ - type: "static" | "dynamic"; - /** - * name of schema that set action for it - */ - schema: string; - /** - * name of action - */ - actName: string; - /** - * validator function for example for validion input date - */ - validator: Struct; + /** + * type of action static or dynamic + * when equal to static for get static file (isdb) + * else for dynamic request(request to db ideed) + */ + type: "static" | "dynamic"; + /** + * name of schema that set action for it + */ + schema: string; + /** + * name of action + */ + actName: string; + /** + * validator function for example for validion input date + */ + validator: Struct; - /** - * function - */ - fn: ActFn; + /** + * function + */ + fn: ActFn; + + /** + * these functions use to implement somthing in context before run fn + */ + preAct?: Function[]; } diff --git a/src/context.ts b/src/context.ts new file mode 100644 index 00000000..a79ef200 --- /dev/null +++ b/src/context.ts @@ -0,0 +1,65 @@ +/// context type ---- +// + +import { LesanContenxt } from "./types.ts"; + +/** + * variable of context + * @defaultValue + * the value of context is '{}' + */ +let context: LesanContenxt = { + Headers: new Headers(), +}; + +/** + * @returns The contextObj + */ +const getContextModel = () => context; + +/** + * @returns The contextObj + */ +const setContext = ( + obj: Record, +) => (context = { ...getContextModel(), ...obj }); +/** + * asigne all of value that we want to carry + * @param con - objects of key , value + * @returns nothing + */ +const addContexts = (con: LesanContenxt) => context = con; + +/** + * add values to previous values that we want to carry + * @param con - objects of key , value + * @returns nothing + */ +const addContext = (con: LesanContenxt) => context = { ...context, con }; +/** + * add Request to Context because the requeste may be required in later functions + * @param con - request of user + * @returns nothing + */ +const addReqToContext = (con: Request) => context["Request"] = con; + +/** + * add Request Header to Context because the requeste may be required in later functions + * @param con - Headers of user + * @returns nothing + */ +const addHeaderToContext = (con: Headers) => context["Headers"] = con; + +/** + * this function is create for define all things in local scope + * and also all functions of context define in this function + * @returns - return objects of all functions that define in this function + */ +export const contextFns = { + getContextModel, + setContext, + addContexts, + addContext, + addReqToContext, + addHeaderToContext, +}; diff --git a/src/lesan.ts b/src/lesan.ts index 7320d776..eaafe185 100644 --- a/src/lesan.ts +++ b/src/lesan.ts @@ -1,4 +1,5 @@ import { acts, Services } from "./acts/mod.ts"; +import { contextFns } from "./context.ts"; import { Database } from "./deps.ts"; import { Model, schemas } from "./models/mod.ts"; import { odm } from "./odm/mod.ts"; @@ -20,6 +21,7 @@ export const lesan = () => { schemas: { ...schemas(schemasObj) }, odm: { ...odm(schemasObj) }, runServer: lesanServer(schemasObj, actsObj), + contextFns, generateSchemTypes: generateSchemTypes(schemasObj), }; }; diff --git a/src/mod.ts b/src/mod.ts index 9b04e148..acf38890 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -10,3 +10,4 @@ export * from "./acts/types.ts"; export * from "./deps.ts"; export * from "./lesan.ts"; export * from "./models/types.ts"; +export * from "./types.ts"; diff --git a/src/models/context.ts b/src/models/context.ts deleted file mode 100644 index 0dc174a9..00000000 --- a/src/models/context.ts +++ /dev/null @@ -1,62 +0,0 @@ -/// context type ---- -// -/** - * Context Holds values and carries them in functions. - * @example - * { - * Request: "values of Req", - * user: { - * "_id":1, - * "name":"ali", - * "lastName":"Alavi" - * "role":"Admin" - * } * - */ -export interface Context { - [key: string]: any; -} - -/** - * this function is create for define all things in local scope - * and also all functions of context define in this function - * @returns - return objects of all functions that define in this function - */ -export const contextFns = () => { - /** - * variable of context - * @defaultValue - * the value of context is '{}' - */ - let context: Context = {}; - - /** - * @returns The contextObj - */ - const getContextModel = () => context; - /** - * asigne all of value that we want to carry - * @param con - objects of key , value - * @returns nothing - */ - const addContexts = (con: Context) => context = con; - - /** - * add values to previous values that we want to carry - * @param con - objects of key , value - * @returns nothing - */ - const addContext = (con: Context) => context = { ...context, con }; - /** - * add Request to Context because the requeste may be required in later functions - * @param con - request of user - * @returns nothing - */ - const addReqToContext = (con: Request) => context["Request"] = con; - - return { - getContextModel, - addContexts, - addContext, - addReqToContext, - }; -}; diff --git a/src/models/inrelation/addInrelations.ts b/src/models/inrelation/addInrelations.ts index 2da54070..8fdd29ac 100644 --- a/src/models/inrelation/addInrelations.ts +++ b/src/models/inrelation/addInrelations.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; import { InRelation } from "./../types.ts"; /** * asign inrelation of schema that schema has relation with it example of relation of SQL that we keep foriegn key. diff --git a/src/models/inrelation/addOneInRelation.ts b/src/models/inrelation/addOneInRelation.ts index 7d5ac94c..0e9d5c91 100644 --- a/src/models/inrelation/addOneInRelation.ts +++ b/src/models/inrelation/addOneInRelation.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; /** * add one innerRelation to previous inrelation of schema that schema has relation with it example of relation of SQL that we keep foriegn key. diff --git a/src/models/inrelation/getInrelations.ts b/src/models/inrelation/getInrelations.ts index 508d4c80..7baf10fc 100644 --- a/src/models/inrelation/getInrelations.ts +++ b/src/models/inrelation/getInrelations.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; /** * get all of inerRealation of one schema diff --git a/src/models/mod.ts b/src/models/mod.ts index 6255c62e..b56a3bc3 100644 --- a/src/models/mod.ts +++ b/src/models/mod.ts @@ -1,4 +1,3 @@ -import { contextFns } from "./context.ts"; import { inrelationFns } from "./inrelation/mod.ts"; import { outrelationFns } from "./outrelation/mod.ts"; import { pureFns } from "./pure/mod.ts"; @@ -17,7 +16,6 @@ export const schemas = (schemas: ISchema) => { return { ...schemaFns(schemas), ...inrelationFns(schemas), - ...contextFns(), ...outrelationFns(schemas), ...pureFns(schemas), ...relationFns(schemas), diff --git a/src/models/outrelation/addOneOutRelation.ts b/src/models/outrelation/addOneOutRelation.ts index 16273e44..f29a3076 100644 --- a/src/models/outrelation/addOneOutRelation.ts +++ b/src/models/outrelation/addOneOutRelation.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; /** * add addOneOutRelation to previous outrelation of schema. diff --git a/src/models/outrelation/addOutRelations.ts b/src/models/outrelation/addOutRelations.ts index 9e1dfe7b..082518de 100644 --- a/src/models/outrelation/addOutRelations.ts +++ b/src/models/outrelation/addOutRelations.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; import { OutRelation } from "../types.ts"; /** diff --git a/src/models/outrelation/getOutRelations.ts b/src/models/outrelation/getOutRelations.ts index a3dac1fc..f9d4b725 100644 --- a/src/models/outrelation/getOutRelations.ts +++ b/src/models/outrelation/getOutRelations.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; /** * getOutRelations of one schema diff --git a/src/models/pure/addPureModel.ts b/src/models/pure/addPureModel.ts index b3d01518..fbaed890 100644 --- a/src/models/pure/addPureModel.ts +++ b/src/models/pure/addPureModel.ts @@ -1,5 +1,4 @@ -import { ISchema, PureModel } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, PureModel, schemaFns } from "../mod.ts"; /** * add pure feature of model to schema diff --git a/src/models/pure/getPureModel.ts b/src/models/pure/getPureModel.ts index 6ef85bbb..04373906 100644 --- a/src/models/pure/getPureModel.ts +++ b/src/models/pure/getPureModel.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; /** * get pure features of one schema diff --git a/src/models/pure/getPureModelByNameAndKey.ts b/src/models/pure/getPureModelByNameAndKey.ts index e32acfbd..0307d013 100644 --- a/src/models/pure/getPureModelByNameAndKey.ts +++ b/src/models/pure/getPureModelByNameAndKey.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; /** * get pure one feature of one schema by name of schema and key of feature diff --git a/src/models/relation/getRelation.ts b/src/models/relation/getRelation.ts index 14c6dc8d..587473ea 100644 --- a/src/models/relation/getRelation.ts +++ b/src/models/relation/getRelation.ts @@ -1,5 +1,4 @@ -import { ISchema } from "../mod.ts"; -import { schemaFns } from "../schema.ts"; +import { ISchema, schemaFns } from "../mod.ts"; /** * get inerRelatrion or outerRealtion of one schema diff --git a/src/odm/mod.ts b/src/odm/mod.ts index fc86f4ac..64d6ef97 100644 --- a/src/odm/mod.ts +++ b/src/odm/mod.ts @@ -13,7 +13,7 @@ import { UpdateOptions, } from "../deps.ts"; import { InRelation, ISchema, OutRelation, PureModel } from "../models/mod.ts"; -import { schemaFns } from "../models/schema.ts"; +import { schemaFns } from "../models/mod.ts"; import { throwError } from "../utils/throwError.ts"; import { addOutrelation, diff --git a/src/odm/utils/addOutrelation.ts b/src/odm/utils/addOutrelation.ts index ecf6675a..36eb8473 100644 --- a/src/odm/utils/addOutrelation.ts +++ b/src/odm/utils/addOutrelation.ts @@ -1,5 +1,4 @@ import { Bson } from "../../deps.ts"; -import { schemaFns } from "../../models/schema.ts"; export const addOutrelation = ( schemaName: string, diff --git a/src/odm/utils/checkInsertRelation.ts b/src/odm/utils/checkInsertRelation.ts index 7fdac4bc..0b24a701 100644 --- a/src/odm/utils/checkInsertRelation.ts +++ b/src/odm/utils/checkInsertRelation.ts @@ -1,5 +1,5 @@ import { Bson, Database } from "../../deps.ts"; -import { schemaFns } from "../../models/schema.ts"; +import { schemaFns } from "../../models/mod.ts"; import { getPureFromDoc } from "./mod.ts"; export const checkRelation = ( diff --git a/src/odm/utils/getPureFromDoc.ts b/src/odm/utils/getPureFromDoc.ts index fc5aaf39..2b542719 100644 --- a/src/odm/utils/getPureFromDoc.ts +++ b/src/odm/utils/getPureFromDoc.ts @@ -1,4 +1,4 @@ -import { schemaFns } from "../../models/schema.ts"; +import { schemaFns } from "../../models/mod.ts"; export const getPureFromDoc = ( collectionName: string, diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..d3809372 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,16 @@ +/** + * Context Holds values and carries them in functions. + * @example + * { + * Request: "values of Req", + * user: { + * "_id":1, + * "name":"ali", + * "lastName":"Alavi" + * "role":"Admin" + * } * + */ +export interface LesanContenxt { + [key: string]: any; + Headers: Headers; +} diff --git a/src/utils/checkWants.ts b/src/utils/checkWants.ts index 041b5fbb..3019dad1 100644 --- a/src/utils/checkWants.ts +++ b/src/utils/checkWants.ts @@ -5,111 +5,111 @@ import { throwError } from "./mod.ts"; * @public */ export interface Details { - /** - * set of query - */ - set: Record; - /** - * get pf query - * What the client wants to return - */ - get: Record; + /** + * set of query + */ + set: Record; + /** + * get pf query + * What the client wants to return + */ + get: Record; } /** * interface is type of input of Actions * @public */ export interface Body { - /** - * name of service - * "main" | "blog" | "ecommerce" - */ - service?: string; - /** - * type of contents : dynamic | static - */ - contents: "dynamic" | "static"; - /** - * model : schema name that client wants - * act : name of Actions - */ - wants: { - model: string; - act: string; - }; - /** - * details of request set and get - */ - details: Details; + /** + * name of service + * "main" | "blog" | "ecommerce" + */ + service?: string; + /** + * type of contents : dynamic | static + */ + contents: "dynamic" | "static"; + /** + * model : schema name that client wants + * act : name of Actions + */ + wants: { + model: string; + act: string; + }; + /** + * details of request set and get + */ + details: Details; } const decodeBody = async (req: Request): Promise => { - /** - * @function - * decode body of request when content type is application/json - */ - const decodeJsonBody = async () => - req.body - ? JSON.parse(await req.text()) as Body - : throwError("Your request body is incorrect"); - - /** - * @function - * decode all files and funql body when type of content type is multipart/form-data - * @remarks it puts all of files in set of details of request body - * @return parsed body with uploaded files - * @example we recommend to use postman or other client lib fot handling boundary field and other fields - */ - const decodeMultiPartBody = async () => { - // finds boundary of form data - // const boundary = contentType.match(/boundary=([^\s]+)/)?.[1]; + /** + * @function + * decode body of request when content type is application/json + */ + const decodeJsonBody = async () => + req.body + ? JSON.parse(await req.text()) as Body + : throwError("Your request body is incorrect"); - const getFileFormData: () => Promise = async () => { - const fd = await req.formData(); - // for (const f of fd.entries()) { - // if (!(f[1] instanceof File)) { - // continue; - // } - // const fileData = new Uint8Array(await f[1].arrayBuffer()); - // await Deno.writeFile("./files/" + f[1].name, fileData); - // } - const returnBody: (body: string) => Body = (body) => { - const parsedBody = JSON.parse(body) as Body; - parsedBody - && parsedBody.details - && parsedBody.details.set - && (parsedBody.details.set = { - ...parsedBody.details.set, - formData: fd, - }); - return parsedBody; - }; + /** + * @function + * decode all files and funql body when type of content type is multipart/form-data + * @remarks it puts all of files in set of details of request body + * @return parsed body with uploaded files + * @example we recommend to use postman or other client lib fot handling boundary field and other fields + */ + const decodeMultiPartBody = async () => { + // finds boundary of form data + // const boundary = contentType.match(/boundary=([^\s]+)/)?.[1]; - const body = fd.get("lesan-body") ? fd.get("lesan-body") as string : "{}"; + const getFileFormData: () => Promise = async () => { + const fd = await req.formData(); + // for (const f of fd.entries()) { + // if (!(f[1] instanceof File)) { + // continue; + // } + // const fileData = new Uint8Array(await f[1].arrayBuffer()); + // await Deno.writeFile("./files/" + f[1].name, fileData); + // } + const returnBody: (body: string) => Body = (body) => { + const parsedBody = JSON.parse(body) as Body; + parsedBody && + parsedBody.details && + parsedBody.details.set && + (parsedBody.details.set = { + ...parsedBody.details.set, + formData: fd, + }); + return parsedBody; + }; - return body - ? returnBody(body) - : throwError("somthing wrong with your file"); - }; + const body = fd.get("lesan-body") ? fd.get("lesan-body") as string : "{}"; - return req.body - ? await getFileFormData() - : throwError("Your body is incorrect"); + return body + ? returnBody(body) + : throwError("somthing wrong with your file"); }; - const contentType = req.headers.get("content-type") || ""; - return contentType.includes("application/json") - ? await decodeJsonBody() - : contentType.includes("multipart/form-data") - ? await decodeMultiPartBody() - : throwError("content type is not correct"); + return req.body + ? await getFileFormData() + : throwError("Your body is incorrect"); + }; + + const contentType = req.headers.get("content-type") || ""; + return contentType.includes("application/json") + ? await decodeJsonBody() + : contentType.includes("multipart/form-data") + ? await decodeMultiPartBody() + : throwError("content type is not correct"); }; export const parsBody = async (req: Request, port: number) => { - const parsedBody = await decodeBody(req); - const url = req.url.split(`${port}`)[1]; + const parsedBody = await decodeBody(req); + const url = req.url.split(`${port}`)[1]; - return req.method === "POST" && url === "/lesan" - ? parsedBody - : throwError("you most send a post request to /lesan url"); + return req.method === "POST" && url === "/lesan" + ? parsedBody + : throwError("you most send a post request to /lesan url"); }; diff --git a/src/utils/serveLesan.ts b/src/utils/serveLesan.ts index af6d6c9a..d7f8e048 100644 --- a/src/utils/serveLesan.ts +++ b/src/utils/serveLesan.ts @@ -1,7 +1,14 @@ import { acts, Services } from "../acts/mod.ts"; +import { contextFns } from "../context.ts"; import { assert, enums } from "../deps.ts"; import { Body, parsBody } from "./mod.ts"; +const runPreActs = async (preActs: Function[]) => { + for (const func of preActs) { + await func(); + } +}; + /** * function of lesan * @param actsObj -all services @@ -28,6 +35,8 @@ export const lesanFns = (actsObj: Services) => { ); assert(body.details, act.validator); + act.preAct && await runPreActs(act.preAct); + return await act.fn(body); }; @@ -149,6 +158,7 @@ export const lesanFns = (actsObj: Services) => { */ const serveLesan = async (req: Request, port: number) => { const response = async () => { + contextFns.addHeaderToContext(req.headers); return await checkServices(req, port); };