diff --git a/.vscode/settings.json b/.vscode/settings.json index e2c0be0..97c3e4c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,20 +1,24 @@ { "files.exclude": { - "**/.git": false, - "**/.svn": false, - "**/.hg": false, - "**/CVS": false, - "**/__pycache__": false, - "test/*context.*": false, - "test/*mocks": false, - "test/*mocks.*": false, - "test/*test": false, - "test/*test.*": false, - "test/*test.js": false, - "test/*test.js.*": false, - "test/*todo": false, - "test/*todo.*": false, - "**/*.js": true, - "**/*.map": true + "server/build/src/core/*controllers.*": true, + "server/build/src/core/*di": true, + "server/build/src/core/*di.*": true, + "server/build/src/core/*extensions": true, + "server/build/src/core/*extensions.*": true, + "server/build/src/core/*helper": true, + "server/build/src/core/*helper.*": true, + "server/build/src/core/*interfaces": true, + "server/build/src/core/*interfaces.*": true, + "server/build/src/core/*middlewares": true, + "server/build/src/core/*middlewares.*": true, + "server/build/src/core/*model": true, + "server/build/src/core/*model.*": true, + "server/build/src/core/*services": true, + "server/build/src/core/*services.*": true, + "server/build/src/core/*usecases": true, + "server/build/src/core/*usecases.*": true, + "server/src/core/model/exec_error_model.js": true, + "**/*.map": true, + "**/*.js": true } } \ No newline at end of file diff --git a/server/.gitignore b/server/.gitignore index 4d4a8bd..64a820b 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -6,3 +6,5 @@ node_modules/ coverage package-lock.json .*.swp +build/ +model_create.ts \ No newline at end of file diff --git a/server/package.json b/server/package.json index 3a35aae..868174c 100644 --- a/server/package.json +++ b/server/package.json @@ -1,18 +1,20 @@ { "name": "step-by-step-server", "version": "0.0.1", - "type": "module", "description": "", "main": "index.js", "scripts": { "pretest": "tsc", - "test": "node ./test/test.js", - "test:watch": "tsc-watch --onSuccess 'node ./test/test.js'" + "test": "ts-node ./build/test/test.js", + "test:watch": "tsc-watch --onSuccess 'ts-node ./build/test/test.js'", + "dev": "tsc-watch --onSuccess 'ts-node ./build/src/main.js'" }, "author": "IDONTSUDO", "devDependencies": { "@testdeck/mocha": "latest", "@types/chai": "latest", + "@types/cors": "^2.8.14", + "@types/express": "^4.17.18", "@types/md5": "^2.3.2", "@types/mocha": "latest", "@types/node": "^20.4.8", @@ -23,20 +25,30 @@ "mocha": "latest", "nyc": "latest", "source-map-support": "latest", + "ts-node": "^10.9.1", "tslint": "latest", "typescript": "^5.1.6" }, "dependencies": { "@grpc/grpc-js": "^1.9.0", "babel-register": "^6.26.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", "concurrently": "^8.2.0", + "cors": "^2.8.5", + "express": "^4.18.2", "first-di": "^1.0.11", "md5": "^2.3.0", + "mongoose": "^7.6.2", + "mongoose-autopopulate": "^1.1.0", "node-watch": "^0.7.4", "nodemon": "^3.0.1", "reflect-metadata": "^0.1.13", + "socket.io": "^4.7.2", + "socket.io-client": "^4.7.2", "spark-md5": "^3.0.2", "ts-md5": "^1.3.1", - "tsc-watch": "^6.0.4" + "tsc-watch": "^6.0.4", + "typedi": "^0.10.0" } } diff --git a/server/src/core/controllers/app.ts b/server/src/core/controllers/app.ts new file mode 100644 index 0000000..d868669 --- /dev/null +++ b/server/src/core/controllers/app.ts @@ -0,0 +1,82 @@ +import express from "express"; +import { Routes } from "../interfaces/router"; +import cors from "cors"; +import locator from "../di/register_di"; +import { DevEnv, UnitTestEnv } from "../di/env"; +import mongoose from "mongoose"; +import http from "http"; +// import { Server } from "socket.io"; + +export class App { + public app: express.Application; + public port: number; + public env: string; + public computedFolder: string; + // public io: + constructor(routes: Routes[], computedFolder: string) { + this.port = 3000; + this.env = "dev"; + this.loadAppDependencies().then(() => { + this.app = express(); + this.initializeMiddlewares(); + this.initializeRoutes(routes); + this.computedFolder = computedFolder; + }); + } + + public listen() { + const httpServer = new http.Server(this.app); + // const io = new Server(httpServer); + + httpServer.listen(this.port, () => { + console.info(`=================================`); + console.info(`======= ENV: ${this.env} =======`); + console.info(`🚀 HTTP http://localhost:${this.port}`); + console.info(`🚀 WS ws://localhost:${this.port}`); + console.info(`=================================`); + }); + // io.on("connection", (socket) => { + // socket.on("disconnect", function (msg) { + // console.log("Disconnected"); + // }); + // }); + + // setInterval(function () { + // io.emit("goodbye"); + // console.log(200); + // }, 1000); + } + + public getServer() { + return this.app; + } + + private initializeMiddlewares() { + this.app.use(cors()); + this.app.use(express.json()); + this.app.use(express.urlencoded({ extended: true })); + } + + private initializeRoutes(routes: Routes[]) { + routes.forEach((route) => { + this.app.use("/", route.router); + }); + } + async loadAppDependencies() { + await locator( + this.env == "development" + ? new DevEnv(this.computedFolder) + : new UnitTestEnv(this.computedFolder) + ); + + mongoose + .connect("mongodb://127.0.0.1:27017/test") + .then(() => console.log("Connected!")) + .catch((e) => { + console.log("ERROR:", e); + }); + } +} + + + \ No newline at end of file diff --git a/server/src/core/controllers/crud_controller.ts b/server/src/core/controllers/crud_controller.ts new file mode 100644 index 0000000..d2ebacc --- /dev/null +++ b/server/src/core/controllers/crud_controller.ts @@ -0,0 +1,34 @@ +import { IRouteModel } from "../interfaces/router"; +import { CreateDataBaseModelUseCase } from "../usecases/create_database_model_usecase"; +import { DeleteDataBaseModelUseCase } from "../usecases/delete_database_model_usecase"; +import { PaginationDataBaseModelUseCase } from "../usecases/pagination_database_model_usecase"; +import { UpdateDataBaseModelUseCase } from "../usecases/update_database_model_usecase"; + +import { CoreHttpController } from "./http_controller"; +import mongoose from "mongoose"; + +export class CrudController extends CoreHttpController { + dataBaseModel: mongoose.Model; + + constructor(routerModel: IRouteModel) { + super(routerModel); + this.url = "/" + routerModel.url; + this.validationModel = routerModel.validationModel; + this.dataBaseModel = routerModel.databaseModel; + this.init(); + } + init() { + this.routes["POST"] = new CreateDataBaseModelUseCase( + this.dataBaseModel + ).call; + this.routes["GET"] = new PaginationDataBaseModelUseCase( + this.dataBaseModel + ).call; + this.routes["DELETE"] = new DeleteDataBaseModelUseCase( + this.dataBaseModel + ).call; + this.routes["PUT"] = new UpdateDataBaseModelUseCase( + this.dataBaseModel + ).call; + } +} diff --git a/server/src/core/controllers/http_controller.ts b/server/src/core/controllers/http_controller.ts new file mode 100644 index 0000000..55fbce9 --- /dev/null +++ b/server/src/core/controllers/http_controller.ts @@ -0,0 +1,107 @@ +import { validationModelMiddleware } from "../middlewares/validation_model"; +import { Result } from "../helper/result"; +import { Router, Request, Response } from "express"; +import { IRouteModel, Routes } from "../interfaces/router"; + +export type CallBackFunction = (a: T) => Promise>; + +abstract class ICoreHttpController { + abstract url: string; + public router = Router(); + abstract call(): Routes; +} + +export class CoreHttpController implements ICoreHttpController { + url: string; + validationModel: any; + + routes = { + POST: null, + GET: null, + DELETE: null, + PUT: null, + }; + + public router = Router(); + + constructor(routerModel: IRouteModel) { + this.url = "/" + routerModel.url; + this.validationModel = routerModel.validationModel; + } + + call(): Routes { + if (this.routes["POST"] != null) { + this.router.post( + this.url, + validationModelMiddleware(this.validationModel), + (req, res) => + this.requestResponseController(req, res, this.routes["POST"]) + ); + } + if (this.routes["DELETE"] != null) { + this.router.delete(this.url, (req, res) => + this.requestResponseController(req, res, this.routes["DELETE"]) + ); + } + if (this.routes["PUT"] != null) { + this.router.put( + this.url, + validationModelMiddleware(this.validationModel), + (req, res) => + this.requestResponseController(req, res, this.routes["PUT"]) + ); + } + if (this.routes["GET"] != null) { + this.router.get(this.url, (req, res) => + this.requestResponseController(req, res, this.routes["GET"]) + ); + } + + return { + router: this.router, + }; + } + public put(usecase: CallBackFunction) { + this.routes["PUT"] = usecase; + } + public delete(usecase: CallBackFunction) { + this.routes["DELETE"] = usecase; + } + private async requestResponseController( + req: Request, + res: Response, + usecase: CallBackFunction + ) { + let payload = null; + + if (req["model"] != undefined) { + payload = req.body as T; + } + + if (req.query.page !== undefined) { + payload = String(req.query.page); + } + + if (req.query.id !== undefined) { + payload = String(req.query.id); + } + + (await usecase(payload)).fold( + (ok) => { + res.json(ok); + return; + }, + (err) => { + res.status(400).json(err); + return; + } + ); + } + public post(usecase: CallBackFunction) { + this.routes["POST"] = usecase; + } + + public get(usecase: CallBackFunction) { + this.routes["GET"] = usecase; + } +} diff --git a/server/src/core/controllers/socket_controller.ts b/server/src/core/controllers/socket_controller.ts new file mode 100644 index 0000000..9e20248 --- /dev/null +++ b/server/src/core/controllers/socket_controller.ts @@ -0,0 +1,15 @@ +// import path from "path"; +// import { TypedEvent } from "../helper/typed_event"; +// import { StackService } from "../services/stack_service"; +// // TODO(IDONTSUDO): up to do + +// class SocketController{ +// emitter:TypedEvent; +// constructor(emitter:TypedEvent, ){ +// this.emitter = emitter +// } +// call = () =>{ + +// } +// } + \ No newline at end of file diff --git a/server/src/core/di/env.ts b/server/src/core/di/env.ts index 8082916..55841e6 100644 --- a/server/src/core/di/env.ts +++ b/server/src/core/di/env.ts @@ -1,6 +1,6 @@ -import { reflection } from "first-di"; +import { Service } from "typedi"; -@reflection +@Service() export class IEnv{ rootFolder!: string; constructor(){ @@ -14,7 +14,7 @@ export class IEnv{ } } -@reflection +@Service() export class DevEnv implements IEnv { rootFolder:string; constructor(rootFolder:string){ @@ -28,8 +28,7 @@ export class DevEnv implements IEnv { } } - -@reflection +@Service() export class UnitTestEnv implements IEnv{ rootFolder:string; constructor(rootFolder:string){ diff --git a/server/src/core/di/register_di.ts b/server/src/core/di/register_di.ts index b08da3a..77c6b6d 100644 --- a/server/src/core/di/register_di.ts +++ b/server/src/core/di/register_di.ts @@ -1,7 +1,6 @@ -import { override } from "first-di"; -import { DevEnv, IEnv, UnitTestEnv } from "./env.js"; -import { MetaDataFileManagerModel } from "../model/meta_data_file_manager_model.js"; -import { extensions } from "../extensions/extensions.js"; +import { DevEnv, IEnv, UnitTestEnv } from "./env"; +import { extensions } from "../extensions/extensions"; +// import { Container, Service } from 'typedi'; export default function locator(env: IEnv) { extensions(); @@ -9,16 +8,16 @@ export default function locator(env: IEnv) { registerRepository(env); registerController(env); registerService(env); - override(MetaDataFileManagerModel, MetaDataFileManagerModel); + // override(MetaDataFileManagerModel, MetaDataFileManagerModel); } const envRegister = (env: IEnv) => { switch (env.toStringEnv()) { case UnitTestEnv.env(): - override(IEnv, UnitTestEnv); + // override(IEnv, UnitTestEnv); return; case "DevEnv": - override(IEnv, DevEnv); + // override(IEnv, DevEnv); return; } }; @@ -26,11 +25,11 @@ const envRegister = (env: IEnv) => { const registerRepository = (env: IEnv) => { switch (env.toStringEnv()) { case UnitTestEnv.env(): - override(IEnv, UnitTestEnv); + // override(IEnv, UnitTestEnv); return; case DevEnv.env(): - override(IEnv, DevEnv); + // override(IEnv, DevEnv); return; } }; diff --git a/server/src/core/extensions/extensions.ts b/server/src/core/extensions/extensions.ts index 0a7d97a..c02556b 100644 --- a/server/src/core/extensions/extensions.ts +++ b/server/src/core/extensions/extensions.ts @@ -1,5 +1,6 @@ -import { ArrayEquals } from "./array.js"; +import { ArrayEquals } from "./array"; export const extensions = () =>{ ArrayEquals() -} \ No newline at end of file +} + \ No newline at end of file diff --git a/server/src/core/helper/cancelable_promise.ts b/server/src/core/helper/cancelable_promise.ts index 86d59be..0519ecb 100644 --- a/server/src/core/helper/cancelable_promise.ts +++ b/server/src/core/helper/cancelable_promise.ts @@ -1,248 +1 @@ -const toStringTag: typeof Symbol.toStringTag = - typeof Symbol !== 'undefined' ? Symbol.toStringTag : ('@@toStringTag' as any); - -class CancelablePromiseInternal { - #internals: Internals; - #promise: Promise; - - [toStringTag] = 'CancelablePromise'; - - constructor({ - executor = () => {}, - internals = defaultInternals(), - promise = new Promise((resolve, reject) => - executor(resolve, reject, (onCancel) => { - internals.onCancelList.push(onCancel); - }) - ), - }: { - executor?: ( - resolve: (value: T | PromiseLike) => void, - reject: (reason?: any) => void, - onCancel: (cancelHandler: () => void) => void - ) => void; - internals?: Internals; - promise?: Promise; - }) { - this.cancel = this.cancel.bind(this); - this.#internals = internals; - this.#promise = - promise || - new Promise((resolve, reject) => - executor(resolve, reject, (onCancel) => { - internals.onCancelList.push(onCancel); - }) - ); - } - - then( - onfulfilled?: - | (( - value: T - ) => TResult1 | PromiseLike | CancelablePromise) - | undefined - | null, - onrejected?: - | (( - reason: any - ) => TResult2 | PromiseLike | CancelablePromise) - | undefined - | null - ): CancelablePromise { - return makeCancelable( - this.#promise.then( - createCallback(onfulfilled, this.#internals), - createCallback(onrejected, this.#internals) - ), - this.#internals - ); - } - - catch( - onrejected?: - | (( - reason: any - ) => TResult | PromiseLike | CancelablePromise) - | undefined - | null - ): CancelablePromise { - return makeCancelable( - this.#promise.catch(createCallback(onrejected, this.#internals)), - this.#internals - ); - } - - finally( - onfinally?: (() => void) | undefined | null, - runWhenCanceled?: boolean - ): CancelablePromise { - if (runWhenCanceled) { - this.#internals.onCancelList.push(onfinally); - } - return makeCancelable( - this.#promise.finally( - createCallback(() => { - if (onfinally) { - if (runWhenCanceled) { - this.#internals.onCancelList = - this.#internals.onCancelList.filter( - (callback) => callback !== onfinally - ); - } - return onfinally(); - } - }, this.#internals) - ), - this.#internals - ); - } - - cancel(): void { - this.#internals.isCanceled = true; - const callbacks = this.#internals.onCancelList; - this.#internals.onCancelList = []; - for (const callback of callbacks) { - if (typeof callback === 'function') { - try { - callback(); - } catch (err) { - console.error(err); - } - } - } - } - - isCanceled(): boolean { - return this.#internals.isCanceled === true; - } -} - -export class CancelablePromise extends CancelablePromiseInternal { - static all = function all(iterable: any) { - return makeAllCancelable(iterable, Promise.all(iterable)); - } as CancelablePromiseOverloads['all']; - - static allSettled = function allSettled(iterable: any) { - return makeAllCancelable(iterable, Promise.allSettled(iterable)); - } as CancelablePromiseOverloads['allSettled']; - - static any = function any(iterable: any) { - return makeAllCancelable(iterable, Promise.any(iterable)); - } as CancelablePromiseOverloads['any']; - - static race = function race(iterable) { - return makeAllCancelable(iterable, Promise.race(iterable)); - } as CancelablePromiseOverloads['race']; - - static resolve = function resolve(value) { - return cancelable(Promise.resolve(value)); - } as CancelablePromiseOverloads['resolve']; - - static reject = function reject(reason) { - return cancelable(Promise.reject(reason)); - } as CancelablePromiseOverloads['reject']; - - static isCancelable = isCancelablePromise; - - constructor( - executor: ( - resolve: (value: T | PromiseLike) => void, - reject: (reason?: any) => void, - onCancel: (cancelHandler: () => void) => void - ) => void - ) { - super({ executor }); - } -} - -export default CancelablePromise; - -export function cancelable(promise: Promise): CancelablePromise { - return makeCancelable(promise, defaultInternals()); -} - -export function isCancelablePromise(promise: any): boolean { - return ( - promise instanceof CancelablePromise || - promise instanceof CancelablePromiseInternal - ); -} - -function createCallback(onResult: any, internals: Internals):any { - if (onResult) { - return (arg?: any) => { - if (!internals.isCanceled) { - const result = onResult(arg); - if (isCancelablePromise(result)) { - internals.onCancelList.push(result.cancel); - } - return result; - } - return arg; - }; - } -} - -function makeCancelable(promise: Promise, internals: Internals) { - return new CancelablePromiseInternal({ - internals, - promise, - }) as CancelablePromise; -} - -function makeAllCancelable(iterable: any, promise: Promise) { - const internals = defaultInternals(); - internals.onCancelList.push(() => { - for (const resolvable of iterable) { - if (isCancelablePromise(resolvable)) { - resolvable.cancel(); - } - } - }); - return new CancelablePromiseInternal({ internals, promise }); -} - -function defaultInternals(): Internals { - return { isCanceled: false, onCancelList: [] }; -} - -interface Internals { - isCanceled: boolean; - onCancelList: any[]; -} - -interface CancelablePromiseOverloads { - all( - values: T - ): CancelablePromise<{ -readonly [P in keyof T]: Awaited }>; - - allSettled( - values: T - ): CancelablePromise<{ - -readonly [P in keyof T]: PromiseSettledResult>; - }>; - - allSettled( - values: Iterable | CancelablePromise> - ): CancelablePromise>[]>; - - any( - values: T - ): CancelablePromise>; - - any( - values: Iterable | CancelablePromise> - ): CancelablePromise>; - - race( - values: T - ): CancelablePromise>; - - resolve(): CancelablePromise; - - resolve( - value: T | PromiseLike | CancelablePromise - ): CancelablePromise; - - reject(reason?: any): CancelablePromise; -} \ No newline at end of file + \ No newline at end of file diff --git a/server/src/core/helper/worker_computed.ts b/server/src/core/helper/worker_computed.ts index 3d19686..5d1a04e 100644 --- a/server/src/core/helper/worker_computed.ts +++ b/server/src/core/helper/worker_computed.ts @@ -1,6 +1,6 @@ -import { EXEC_EVENT, EXEC_TYPE, ExecError } from "../model/exec_error_model.js"; +import { EXEC_EVENT, EXEC_TYPE, ExecError } from "../model/exec_error_model"; import * as cp from "child_process"; -import { ExecutorResult } from "../model/executor_result.js"; +import { ExecutorResult } from "../model/executor_result"; export enum WorkerType { EXEC = "EXEC", diff --git a/server/src/core/interfaces/payload.ts b/server/src/core/interfaces/payload.ts new file mode 100644 index 0000000..f99acbc --- /dev/null +++ b/server/src/core/interfaces/payload.ts @@ -0,0 +1,14 @@ + +// export class Payload{ +// model: T | undefined +// query:string | undefined +// setModel(model:T){ +// this.model = model +// } +// setQuery(query:string){ +// this.query = query +// } +// isEmpty(){ +// return this.model != undefined || this.query != undefined +// } +// } \ No newline at end of file diff --git a/server/src/core/interfaces/response.ts b/server/src/core/interfaces/response.ts new file mode 100644 index 0000000..1efee99 --- /dev/null +++ b/server/src/core/interfaces/response.ts @@ -0,0 +1,3 @@ +export interface ICreateObjectDataBase { + id: string; +} diff --git a/server/src/core/interfaces/router.ts b/server/src/core/interfaces/router.ts new file mode 100644 index 0000000..ad4dbd4 --- /dev/null +++ b/server/src/core/interfaces/router.ts @@ -0,0 +1,14 @@ +import { Router } from "express"; + +export interface Routes { + router: Router; +} + +export interface IRouteModel { + validationModel: any; + url: string; + databaseModel: any; +} + + + \ No newline at end of file diff --git a/server/src/core/middlewares/validation_auth.ts b/server/src/core/middlewares/validation_auth.ts new file mode 100644 index 0000000..d044c30 --- /dev/null +++ b/server/src/core/middlewares/validation_auth.ts @@ -0,0 +1,12 @@ +// import { RequestHandler } from "express"; + +// export const validationMiddleware = ( +// type: any, +// value = 'body', +// skipMissingProperties = false, +// whitelist = true, +// forbidNonWhitelisted = true, +// ): RequestHandler => { + + +// } \ No newline at end of file diff --git a/server/src/core/middlewares/validation_model.ts b/server/src/core/middlewares/validation_model.ts new file mode 100644 index 0000000..5a58d72 --- /dev/null +++ b/server/src/core/middlewares/validation_model.ts @@ -0,0 +1,30 @@ +import { plainToInstance } from 'class-transformer'; +import { validate, ValidationError } from 'class-validator'; +import { RequestHandler } from 'express'; + +export const validationModelMiddleware = ( + type: any, + value = 'body', + skipMissingProperties = false, + whitelist = true, + forbidNonWhitelisted = true, +): RequestHandler => { + return (req, res, next) => { + if(type === null && type == undefined){ + next() + return + } + const model = plainToInstance(type, req[value]); + validate(model, { skipMissingProperties, whitelist, forbidNonWhitelisted }).then((errors: ValidationError[]) => { + console.log(errors) + if (errors.length > 0) { + const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(', '); + return res.status(400).json(message) + } else { + req['model'] = model + next(); + } + }); + }; +}; + diff --git a/server/src/core/model/executor_result.ts b/server/src/core/model/executor_result.ts index d3c632f..8df94ab 100644 --- a/server/src/core/model/executor_result.ts +++ b/server/src/core/model/executor_result.ts @@ -1,19 +1,18 @@ -import { EXEC_EVENT, EXEC_TYPE } from "./exec_error_model.js"; +import { EXEC_EVENT, EXEC_TYPE } from "./exec_error_model"; - export class ExecutorResult { - type: EXEC_TYPE; - event: EXEC_EVENT; - data: any; - constructor(type: EXEC_TYPE, event: EXEC_EVENT, data: any) { - this.type = type; - this.event = event; - this.data = data; + type: EXEC_TYPE; + event: EXEC_EVENT; + data: any; + constructor(type: EXEC_TYPE, event: EXEC_EVENT, data: any) { + this.type = type; + this.event = event; + this.data = data; + } + static isExecutorResult(value: any): void | ExecutorResult { + if ("type" in value && "event" in value && "data" in value) { + return new ExecutorResult(value.type, value.event, value.data); } - static isExecutorResult(value: any): void | ExecutorResult { - if ("type" in value && "event" in value && "data" in value) { - return new ExecutorResult(value.type, value.event, value.data); - } - return; - } - } \ No newline at end of file + return; + } +} diff --git a/server/src/core/model/process_model.ts b/server/src/core/model/process_model.ts index da2239b..e5fa05f 100644 --- a/server/src/core/model/process_model.ts +++ b/server/src/core/model/process_model.ts @@ -1,16 +1,16 @@ -import { EXEC_TYPE } from "./exec_error_model.js"; +import { Trigger } from "../../features/triggers/trigger_model"; +import { EXEC_TYPE } from "./exec_error_model"; - -export interface ProcessMetaData { - process: Process; +export interface IPipeline { + process: IProcess; trigger: Trigger; env: Env | null; - stackGenerateType:StackGenerateType; + stackGenerateType: StackGenerateType; } -export enum StackGenerateType{ - MAP = 'MAP', - SINGLETON = 'SINGLETON' +export enum StackGenerateType { + MAP = "MAP", + SINGLETON = "SINGLETON", } export interface Env { @@ -19,26 +19,17 @@ export interface Env { isExtends: string; } -export interface Process { - type: EXEC_TYPE; +export interface IProcess { + type: EXEC_TYPE; command: string; isGenerating: boolean; isLocaleCode: boolean; issueType: IssueType; timeout?: number; - commit?:string | undefined; + commit?: string | undefined; } export enum IssueType { WARNING = "WARNING", ERROR = "ERROR", } - -export enum TriggerType { - PROCESS = "PROCESS", - FILE = "FILE", -} -export interface Trigger { - type: TriggerType; - value: string[]; -} diff --git a/server/src/core/services/executor_program_service.ts b/server/src/core/services/executor_program_service.ts index a6f89e2..6107d7d 100644 --- a/server/src/core/services/executor_program_service.ts +++ b/server/src/core/services/executor_program_service.ts @@ -1,10 +1,10 @@ import cluster, { Worker } from "node:cluster"; -import { TypedEvent } from "../helper/typed_event.js"; -import { Result } from "../helper/result.js"; -import { WorkerDataExec, WorkerType } from "../helper/worker_computed.js"; -import { delay } from "../helper/delay.js"; -import { ExecutorResult } from "../model/executor_result.js"; -import { EXEC_TYPE, ExecError, SpawnError } from "../model/exec_error_model.js"; +import { TypedEvent } from "../helper/typed_event"; +import { Result } from "../helper/result"; +import { WorkerDataExec, WorkerType } from "../helper/worker_computed"; +import { delay } from "../helper/delay"; +import { ExecutorResult } from "../model/executor_result"; +import { EXEC_TYPE, ExecError, SpawnError } from "../model/exec_error_model"; abstract class IExecutorProgramService { abstract execPath: string; @@ -31,7 +31,7 @@ export class ExecutorProgramService args: Array | undefined = undefined ) { cluster.setupPrimary({ - exec: "./src/core/helper/worker_computed.js", + exec: "./src/core/helper/worker_computed", }); const worker = cluster.fork(); diff --git a/server/src/core/services/files_change_notifier_service.ts b/server/src/core/services/files_change_notifier_service.ts index 33a3615..af0d397 100644 --- a/server/src/core/services/files_change_notifier_service.ts +++ b/server/src/core/services/files_change_notifier_service.ts @@ -7,16 +7,16 @@ import { BinaryLike } from "crypto"; import { EventsFileChanger, MetaDataFileManagerModel, -} from "../model/meta_data_file_manager_model.js"; -import { Result } from "../helper/result.js"; -import { TypedEvent } from "../helper/typed_event.js"; +} from "../model/meta_data_file_manager_model"; +import { Result } from "../helper/result"; +import { TypedEvent } from "../helper/typed_event"; const readFileAsync = promisify(fs.readFile); const readdir = promisify(fs.readdir); const stat = promisify(fs.stat); const lsStat = promisify(fs.lstat); -function joinBuffers(buffers, delimiter = " ") { +function joinBuffers(buffers: Array, delimiter = " ") { const d = Buffer.from(delimiter); return buffers.reduce((prev, b) => Buffer.concat([prev, d, b])); } @@ -44,8 +44,6 @@ export interface IHashesCache { [key: string]: MetaDataFileManagerModel; } - - export abstract class IFilesChangeNotifierService { abstract directory: string; } diff --git a/server/src/core/services/stack_service.ts b/server/src/core/services/stack_service.ts index a5874c3..ceb6fbf 100644 --- a/server/src/core/services/stack_service.ts +++ b/server/src/core/services/stack_service.ts @@ -1,43 +1,40 @@ import { FilesChangeNotifierService, IHashesCache, -} from "./files_change_notifier_service.js"; -import { ProcessMetaData, Trigger } from "../model/process_model.js"; -import { ExecutorProgramService } from "./executor_program_service.js"; -import { - EXEC_EVENT, - ExecError, - SpawnError, -} from "../model/exec_error_model.js"; -import { TypedEvent } from "../helper/typed_event.js"; -import { Result } from "../helper/result.js"; -import { ExecutorResult } from "../model/executor_result.js"; -import { delay } from "../helper/delay.js"; -import { TriggerErrorReport, TriggerService } from "./trigger_service.js"; +} from "./files_change_notifier_service"; +import { IPipeline } from "../model/process_model"; +import { ExecutorProgramService } from "./executor_program_service"; +import { EXEC_EVENT, ExecError, SpawnError } from "../model/exec_error_model"; +import { TypedEvent } from "../helper/typed_event"; +import { Result } from "../helper/result"; +import { ExecutorResult } from "../model/executor_result"; +import { delay } from "../helper/delay"; +import { TriggerService } from "./trigger_service"; +import { Trigger } from "../../features/triggers/trigger_model"; export interface Iteration { hashes: IHashesCache | null; - process: ProcessMetaData; + process: IPipeline; result?: ExecError | SpawnError | ExecutorResult; } export abstract class IStackService { abstract callStack: Iteration[]; abstract path: string; - abstract init(processed: ProcessMetaData[], path: string): void; + abstract init(processed: IPipeline[], path: string): void; } export class StackService extends TypedEvent implements IStackService { callStack: Iteration[]; path: string; - constructor(processed: ProcessMetaData[], path: string) { + constructor(processed: IPipeline[], path: string) { super(); this.path = path; this.callStack = []; this.init(processed); } - public init(processed: ProcessMetaData[]) { + public init(processed: IPipeline[]) { for (let el of processed) { el = this.commandHandler(el); this.callStack.push({ @@ -46,7 +43,7 @@ export class StackService extends TypedEvent implements IStackService { }); } } - private commandHandler(processMetaData: ProcessMetaData) { + private commandHandler(processMetaData: IPipeline) { processMetaData.process.command = processMetaData.process.command.replace( "$PATH", this.path @@ -91,10 +88,10 @@ export class StackService extends TypedEvent implements IStackService { ); triggerResult.fold( (s) => { - s + s; }, (e) => { - e; + e; } ); } diff --git a/server/src/core/services/trigger_service.ts b/server/src/core/services/trigger_service.ts index 581d96d..0c7b990 100644 --- a/server/src/core/services/trigger_service.ts +++ b/server/src/core/services/trigger_service.ts @@ -1,9 +1,9 @@ -import { Trigger, TriggerType } from "../model/process_model.js"; import * as vm from "node:vm"; -import { IHashesCache } from "./files_change_notifier_service.js"; -import { EventsFileChanger } from "../model/meta_data_file_manager_model.js"; -import { Result } from "../helper/result.js"; -import { TypedEvent } from "../helper/typed_event.js"; +import { IHashesCache } from "./files_change_notifier_service"; +import { EventsFileChanger } from "../model/meta_data_file_manager_model"; +import { Result } from "../helper/result"; +import { TypedEvent } from "../helper/typed_event"; +import { Trigger, TriggerType } from "../../features/triggers/trigger_model"; export class TriggerCallResult { results: Array; @@ -47,7 +47,7 @@ export class TriggerErrorReport extends Error { } } export class TriggerService extends TypedEvent { - context = {}; + context: any = {}; constructor(trigger: Trigger, hashes: IHashesCache, path: string) { super(); @@ -61,8 +61,11 @@ export class TriggerService extends TypedEvent { path: string; hashes: IHashesCache; trigger: Trigger; + private init(): void { - this.context["hashes"] = this.hashes; + if (this.context["hashes"] != undefined) { + this.context["hashes"] = this.hashes; + } } private getAllHashesDeleteWithouts(): string[] { return Object.entries(this.hashes).map(([k, v]) => { diff --git a/server/src/core/usecases/create_database_model_usecase.ts b/server/src/core/usecases/create_database_model_usecase.ts new file mode 100644 index 0000000..a73d071 --- /dev/null +++ b/server/src/core/usecases/create_database_model_usecase.ts @@ -0,0 +1,22 @@ +import { Result } from "../helper/result"; +import { ICreateObjectDataBase } from "../interfaces/response"; + +export class CreateDataBaseModelUseCase { + databaseModel: any; + + constructor(model) { + this.databaseModel = model; + } + + call = async ( + validationModel: V + ): Promise> => { + try { + const result = new this.databaseModel(validationModel); + + return Result.ok({ id: String((await result.save())._id) }); + } catch (error) { + return Result.error(error); + } + }; +} diff --git a/server/src/core/usecases/delete_database_model_usecase.ts b/server/src/core/usecases/delete_database_model_usecase.ts new file mode 100644 index 0000000..abc97a6 --- /dev/null +++ b/server/src/core/usecases/delete_database_model_usecase.ts @@ -0,0 +1,18 @@ + import { Result } from "../helper/result"; + +export class DeleteDataBaseModelUseCase { + databaseModel: D | any; + constructor(model) { + this.databaseModel = model; + } + call = async (id: string): Promise> => { + try { + const model = new this.databaseModel({ _id: id }); + await model.deleteOne(); + + return Result.ok(true); + } catch (error) { + return Result.error(error); + } + }; +} diff --git a/server/src/core/usecases/pagination_database_model_usecase.ts b/server/src/core/usecases/pagination_database_model_usecase.ts new file mode 100644 index 0000000..ada4d6a --- /dev/null +++ b/server/src/core/usecases/pagination_database_model_usecase.ts @@ -0,0 +1,28 @@ +import { Result } from "../helper/result"; + +export class PaginationDataBaseModelUseCase { + databaseModel: D; + perPage: number; + + constructor(model: any, perPage = 10) { + this.databaseModel = model; + this.perPage = perPage; + } + + call = async ( + pageNumber: number + ): Promise> => { + try { + const page = Math.max(0, pageNumber); + const model = this.databaseModel as any; + return Result.ok( + await model + .find() + .limit(this.perPage) + .skip(this.perPage * page) + ); + } catch (error) { + return Result.error(error); + } + }; +} diff --git a/server/src/core/usecases/read_database_model_usecase.ts b/server/src/core/usecases/read_database_model_usecase.ts new file mode 100644 index 0000000..6786b80 --- /dev/null +++ b/server/src/core/usecases/read_database_model_usecase.ts @@ -0,0 +1,20 @@ + +import { Result } from "../helper/result"; + +export class ReadByIdDataBaseModelUseCase { + databaseModel: D; + + constructor(model) { + this.databaseModel = model; + } + call = async (id: string): Promise> => { + try { + const r = this.databaseModel as any; + + const model = await r.findById(id); + return Result.ok(model); + } catch (error) { + return Result.error(error); + } + }; +} diff --git a/server/src/core/usecases/update_database_model_usecase.ts b/server/src/core/usecases/update_database_model_usecase.ts new file mode 100644 index 0000000..a35b788 --- /dev/null +++ b/server/src/core/usecases/update_database_model_usecase.ts @@ -0,0 +1,27 @@ +import { Result } from "../helper/result"; + +interface uuid { + _id?: string; +} + +export class UpdateDataBaseModelUseCase { + databaseModel: D; + constructor(databaseModel) { + this.databaseModel = databaseModel; + } + + call = async (updateModel: T): Promise> => { + try { + if (updateModel["_id"] === undefined) { + return Result.error(new Error("need _id at model body")); + } + const databaseModel = this.databaseModel as any; + const model = await databaseModel.findById(updateModel._id); + Object.assign(model, updateModel); + await model.save(); + return Result.ok(model as T); + } catch (error) { + return Result.error(error); + } + }; +} diff --git a/server/src/features/pipelines/pipeline_model.ts b/server/src/features/pipelines/pipeline_model.ts new file mode 100644 index 0000000..3409dd0 --- /dev/null +++ b/server/src/features/pipelines/pipeline_model.ts @@ -0,0 +1,47 @@ +import { IsMongoId, IsEnum } from "class-validator"; +import { Schema, model } from "mongoose"; +import { StackGenerateType } from "../../core/model/process_model"; +import { + TriggerModel, + triggerSchema, +} from "../triggers/trigger_model"; +import { schemaProcess } from "../process/process_model"; + +export const PipelineSchema = new Schema({ + process: { + type: Schema.Types.ObjectId, + ref: schemaProcess, + autopopulate: true, + default: null, + }, + trigger: { + type: Schema.Types.ObjectId, + ref: triggerSchema, + autopopulate: true, + default: null, + }, + command: { + type: String, + }, +}).plugin(require("mongoose-autopopulate")); + +export const schemaPipeline = "Pipeline"; + +export const PipelineDBModel = model( + schemaPipeline, + PipelineSchema +); + +export class PipelineModel { + @IsMongoId() + public process: PipelineModel; + + @IsMongoId() + //TODO(IDONTSUDO):NEED OPTION DECORATOR?? + public trigger: TriggerModel; + + public env = null; + + @IsEnum(StackGenerateType) + public stackGenerateType: StackGenerateType; +} diff --git a/server/src/features/pipelines/pipeline_presentation.ts b/server/src/features/pipelines/pipeline_presentation.ts new file mode 100644 index 0000000..6476392 --- /dev/null +++ b/server/src/features/pipelines/pipeline_presentation.ts @@ -0,0 +1,16 @@ +import { CrudController } from "../../core/controllers/crud_controller"; +import { PipelineDBModel, PipelineModel } from "./pipeline_model"; + +export class PipelinePresentation extends CrudController< + PipelineModel, + typeof PipelineDBModel +> { + constructor() { + super({ + url: "pipeline", + validationModel: PipelineModel, + databaseModel: PipelineDBModel, + }); + } + +} diff --git a/server/src/features/process/process_model.ts b/server/src/features/process/process_model.ts new file mode 100644 index 0000000..df48590 --- /dev/null +++ b/server/src/features/process/process_model.ts @@ -0,0 +1,69 @@ +import { + IsString, + IsOptional, + IsEnum, + IsNumber, + IsBoolean, +} from "class-validator"; +import { Schema, model } from "mongoose"; +import { + IProcess, + IssueType, +} from "../../core/model/process_model"; +import { EXEC_TYPE } from "../../core/model/exec_error_model"; + +export const ProcessSchema = new Schema({ + type: { + type: String, + }, + command: { + type: String, + }, + isGenerating: { + type: String, + }, + isLocaleCode: { + type: String, + }, + issueType: { + type: String, + }, + timeout: { + type: Number, + default: null, + }, + commit: { + type: String, + default: null, + }, +}); + +export const schemaProcess = "Process"; + +export const ProcessDBModel = model(schemaProcess, ProcessSchema); + +export class ProcessModel implements IProcess { + @IsEnum(EXEC_TYPE) + public type: EXEC_TYPE; + + @IsString() + public command: string; + + @IsBoolean() + public isGenerating: boolean; + + @IsBoolean() + public isLocaleCode: boolean; + + @IsEnum(IssueType) + public issueType: IssueType; + + @IsOptional() + @IsNumber() + public timeout?: number; + + @IsOptional() + @IsString() + public commit?: string; +} + \ No newline at end of file diff --git a/server/src/features/process/process_presentation.ts b/server/src/features/process/process_presentation.ts new file mode 100644 index 0000000..b9ec912 --- /dev/null +++ b/server/src/features/process/process_presentation.ts @@ -0,0 +1,15 @@ +import { CrudController } from "../../core/controllers/crud_controller"; +import { ProcessDBModel, ProcessModel } from "./process_model"; + +export class ProcessPresentation extends CrudController< + ProcessModel, + typeof ProcessDBModel +> { + constructor() { + super({ + url: "process", + validationModel: ProcessModel, + databaseModel: ProcessDBModel, + }); + } +} diff --git a/server/src/features/projects/projects_model.ts b/server/src/features/projects/projects_model.ts new file mode 100644 index 0000000..dfbf035 --- /dev/null +++ b/server/src/features/projects/projects_model.ts @@ -0,0 +1,31 @@ +import { Schema, model } from "mongoose"; +import { PipelineModel, schemaPipeline } from "../pipelines/pipeline_model"; +import { IsMongoId, IsString } from "class-validator"; + +export interface IProjectModel { + pipelines: [PipelineModel]; + rootDir: string; +} + +export const ProjectSchema = new Schema({ + pipelines: { + type: Array, + ref: schemaPipeline, + autopopulate: true, + default: null, + }, + rootDir: { + type: String, + }, +}).plugin(require("mongoose-autopopulate")); + +const schema = "Projects"; + +export const ProjectDBModel = model(schema, ProjectSchema); + +export class ProjectModel implements IProjectModel { + @IsMongoId() + pipelines: [PipelineModel]; + @IsString() + rootDir: string; +} diff --git a/server/src/features/projects/projects_presentation.ts b/server/src/features/projects/projects_presentation.ts new file mode 100644 index 0000000..e9414ad --- /dev/null +++ b/server/src/features/projects/projects_presentation.ts @@ -0,0 +1,16 @@ +// import { TriggerDBModel, TriggerModel } from "./trigger_model"; +import { CrudController } from "../../core/controllers/crud_controller"; +import { ProjectDBModel, ProjectModel } from "./projects_model"; + +export class ProjectsPresentation extends CrudController< + ProjectModel, + typeof ProjectDBModel +> { + constructor() { + super({ + url: "project", + validationModel: ProjectModel, + databaseModel: ProjectDBModel, + }); + } +} diff --git a/server/src/features/triggers/trigger_model.ts b/server/src/features/triggers/trigger_model.ts new file mode 100644 index 0000000..5e25257 --- /dev/null +++ b/server/src/features/triggers/trigger_model.ts @@ -0,0 +1,43 @@ +import { IsArray, IsOptional, IsEnum} from "class-validator"; +import { Schema, model } from "mongoose"; + +export interface ITriggerModel { + _id?: string; + type: string; + value: string[]; +} + +export const TriggerSchema = new Schema({ + type: { + type: String, + require: true, + }, + value: { + type: Array, + require: true, + }, +}); + +export const triggerSchema = "Trigger"; + +export const TriggerDBModel = model(triggerSchema, TriggerSchema); + +export enum TriggerType { + PROCESS = "PROCESS", + FILE = "FILE", +} + +export class TriggerModel implements ITriggerModel { + @IsOptional() + public _id: string; + @IsEnum(TriggerType) + public type: TriggerType; + @IsArray() + public value: string[]; +} + +export interface Trigger { + type: TriggerType; + value: string[]; +} + \ No newline at end of file diff --git a/server/src/features/triggers/triggers_presentation.ts b/server/src/features/triggers/triggers_presentation.ts new file mode 100644 index 0000000..77b135f --- /dev/null +++ b/server/src/features/triggers/triggers_presentation.ts @@ -0,0 +1,15 @@ +import { TriggerDBModel, TriggerModel } from "./trigger_model"; +import { CrudController } from "../../core/controllers/crud_controller"; + +export class TriggerPresentation extends CrudController< + TriggerModel, + typeof TriggerDBModel +> { + constructor() { + super({ + url: "trigger", + validationModel: TriggerModel, + databaseModel: TriggerDBModel, + }); + } +} diff --git a/server/src/index.ts b/server/src/index.ts deleted file mode 100644 index 5f247c2..0000000 --- a/server/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {} \ No newline at end of file diff --git a/server/src/main.ts b/server/src/main.ts new file mode 100644 index 0000000..3d844be --- /dev/null +++ b/server/src/main.ts @@ -0,0 +1,21 @@ +import "reflect-metadata"; +import { App } from "./core/controllers/app"; +import { Routes } from "./core/interfaces/router"; +import { TriggerPresentation } from "./features/triggers/triggers_presentation"; +import { ProjectsPresentation } from "./features/projects/projects_presentation"; +import { PipelinePresentation } from "./features/pipelines/pipeline_presentation"; +import { ProcessPresentation } from "./features/process/process_presentation"; + + +const httpRoutes: Routes[] = [ + new TriggerPresentation(), + new ProjectsPresentation(), + new ProcessPresentation(), + new PipelinePresentation(), +].map((el) => el.call()); + +const computedFolder = ""; + +new App(httpRoutes, computedFolder).listen(); + + \ No newline at end of file diff --git a/server/test/core/test_core.ts b/server/test/core/test_core.ts index a20f87c..8ca7373 100644 --- a/server/test/core/test_core.ts +++ b/server/test/core/test_core.ts @@ -1,6 +1,12 @@ -import { delay } from "../../src/core/helper/delay.js"; +import mongoose from "mongoose"; +import { delay } from "../../src/core/helper/delay"; import { Result } from "../../src/core/helper/result"; -import { TypedEvent } from "../../src/core/helper/typed_event.js"; +import { TypedEvent } from "../../src/core/helper/typed_event"; + + +export const before = async () =>{ + await mongoose.connection.dropDatabase() +} export class TestCore { allTests = 0; @@ -23,7 +29,7 @@ export class TestCore { console.log("\x1b[31m", "❌ - " + testName); }; - testResult = () => { + testResult = async () => { console.log("\x1b[32m", "============="); if (this.allTests - this.testOk === 0) { @@ -37,6 +43,7 @@ export class TestCore { console.log("\x1b[31m", "❌ test error:" + String(this.testErr)); console.log("\x1b[32m", `✅ test success! ${this.testOk}`); } + await before() }; resultTest = async ( eventClass: TypedEvent> | any, diff --git a/server/test/model/test_db_mongo_model.ts b/server/test/model/test_db_mongo_model.ts new file mode 100644 index 0000000..5e2f708 --- /dev/null +++ b/server/test/model/test_db_mongo_model.ts @@ -0,0 +1,15 @@ +import { Schema, model } from "mongoose"; + +export interface ITestModel{ + _id?: string; + result: string; +} + +export const TestSchema = new Schema({ + result: String, +}); + +const schema = "Test"; + +export const TestDBModel = model(schema, TestSchema); + \ No newline at end of file diff --git a/server/test/features/executor_program_service_test.ts b/server/test/services/executor_program_service_test.ts similarity index 88% rename from server/test/features/executor_program_service_test.ts rename to server/test/services/executor_program_service_test.ts index 9e4d106..8cf3849 100644 --- a/server/test/features/executor_program_service_test.ts +++ b/server/test/services/executor_program_service_test.ts @@ -1,9 +1,9 @@ -import { delay } from "../../src/core/helper/delay.js"; -import { EXEC_TYPE } from "../../src/core/model/exec_error_model.js"; -import { ExecutorResult } from "../../src/core/model/executor_result.js"; -import { ExecutorProgramService } from "../../src/core/services/executor_program_service.js"; -import { TestCore } from "../core/test_core.js"; -import { resultTest as resultTest, dirname__ } from "../test.js"; +import { delay } from "../../src/core/helper/delay"; +import { EXEC_TYPE } from "../../src/core/model/exec_error_model"; +import { ExecutorResult } from "../../src/core/model/executor_result"; +import { ExecutorProgramService } from "../../src/core/services/executor_program_service"; +import { TestCore } from "../core/test_core"; +import { resultTest as resultTest, dirname__ } from "../test"; import { Worker } from "node:cluster"; export class ExecutorProgramServiceTest extends ExecutorProgramService { @@ -19,7 +19,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService { dirname__ + "/" ); executorProgramService.call(EXEC_TYPE.SPAWN, "node", [ - "./mocks/log_code.js", + "./mocks/log_code", ]); const test = TestCore.instance; let testIsOk = false; @@ -45,7 +45,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService { const executorProgramService = await new ExecutorProgramService(dirname__); executorProgramService.call( EXEC_TYPE.EXEC, - "node ./test/mocks/log_code.js" + "node ./test/mocks/log_code" ); const test = TestCore.instance; executorProgramService.on((e) => { @@ -63,7 +63,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService { const executorProgramService = await new ExecutorProgramService("", 1000); executorProgramService.call( EXEC_TYPE.EXEC, - "node ./test/mocks/long_code.js" + "node ./test/mocks/long_code" ); await delay(1500); const worker = executorProgramService.worker as Worker; @@ -73,7 +73,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService { private resultsTests = async () => { await resultTest( new ExecutorProgramService(dirname__), - [EXEC_TYPE.EXEC, "node ./mocks/error.js"], + [EXEC_TYPE.EXEC, "node ./mocks/error"], "ExecutorProgramService EXEC_TYPE.EXEC on Result.error", false, 4000 @@ -94,7 +94,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService { ); await resultTest( new ExecutorProgramService(dirname__), - [EXEC_TYPE.SPAWN, "python3 ./mocks/s.js"], + [EXEC_TYPE.SPAWN, "python3 ./mocks/s"], "ExecutorProgramService EXEC_TYPE.SPAWN on Result.error", false, 2000 diff --git a/server/test/features/files_change_notifier_service_test.ts b/server/test/services/files_change_notifier_service_test.ts similarity index 93% rename from server/test/features/files_change_notifier_service_test.ts rename to server/test/services/files_change_notifier_service_test.ts index e47598f..8246820 100644 --- a/server/test/features/files_change_notifier_service_test.ts +++ b/server/test/services/files_change_notifier_service_test.ts @@ -1,8 +1,8 @@ import * as fs from "fs"; -import { FilesChangeNotifierService } from "../../src/core/services/files_change_notifier_service.js"; -import { EventsFileChanger } from "../../src/core/model/meta_data_file_manager_model.js"; -import { assert, dirname__ } from "../test.js"; -import { delay } from "../../src/core/helper/delay.js"; +import { FilesChangeNotifierService } from "../../src/core/services/files_change_notifier_service"; +import { EventsFileChanger } from "../../src/core/model/meta_data_file_manager_model"; +import { assert, dirname__ } from "../test"; +import { delay } from "../../src/core/helper/delay"; export class FilesChangerTest extends FilesChangeNotifierService { directory = dirname__ + "/context/"; diff --git a/server/test/features/stack_service_test.ts b/server/test/services/stack_service_test.ts similarity index 92% rename from server/test/features/stack_service_test.ts rename to server/test/services/stack_service_test.ts index 1cf468f..12a25f8 100644 --- a/server/test/features/stack_service_test.ts +++ b/server/test/services/stack_service_test.ts @@ -4,12 +4,12 @@ import * as fs from "fs"; import { IssueType, StackGenerateType, - TriggerType, -} from "../../src/core/model/process_model.js"; -import { EXEC_TYPE } from "../../src/core/model/exec_error_model.js"; -import { StackService } from "../../src/core/services/stack_service.js"; -import { delay } from "../../src/core/helper/delay.js"; -import { assert, dirname__ } from "../test.js"; +} from "../../src/core/model/process_model"; +import { EXEC_TYPE } from "../../src/core/model/exec_error_model"; +import { StackService } from "../../src/core/services/stack_service"; +import { delay } from "../../src/core/helper/delay"; +import { assert, dirname__ } from "../test"; +import { TriggerType } from "../../src/features/triggers/trigger_model"; abstract class IStackServiceTest { abstract test(): Promise; diff --git a/server/test/features/trigger_service_test.ts b/server/test/services/trigger_service_test.ts similarity index 93% rename from server/test/features/trigger_service_test.ts rename to server/test/services/trigger_service_test.ts index 1c12595..d919256 100644 --- a/server/test/features/trigger_service_test.ts +++ b/server/test/services/trigger_service_test.ts @@ -1,10 +1,11 @@ import { EventsFileChanger, MetaDataFileManagerModel, -} from "../../src/core/model/meta_data_file_manager_model.js"; -import { TriggerType } from "../../src/core/model/process_model.js"; -import { TriggerService } from "../../src/core/services/trigger_service.js"; -import { assert } from "../test.js"; +} from "../../src/core/model/meta_data_file_manager_model"; + +import { TriggerService } from "../../src/core/services/trigger_service"; +import { TriggerType } from "../../src/features/triggers/trigger_model"; +import { assert } from "../test"; abstract class TriggerTest { abstract test(): Promise; } diff --git a/server/test/test.ts b/server/test/test.ts index 0d5f165..f29630a 100644 --- a/server/test/test.ts +++ b/server/test/test.ts @@ -1,17 +1,21 @@ -import locator from "../src/core/di/register_di.js"; -import { UnitTestEnv } from "../src/core/di/env.js"; -import { fileURLToPath } from "url"; +import { TestCore } from "./core/test_core"; +import { UnitTestEnv } from "../src/core/di/env"; import { dirname } from "path"; -import { ExecutorProgramServiceTest } from "./features/executor_program_service_test.js"; -import { FilesChangerTest } from "./features/files_change_notifier_service_test.js"; -import { TestCore } from "./core/test_core.js"; -import "reflect-metadata"; -import { StackServiceTest } from "./features/stack_service_test.js"; -import { TriggerServiceTest } from "./features/trigger_service_test.js"; +import locator from "../src/core/di/register_di"; +import { ExecutorProgramServiceTest } from "./services/executor_program_service_test"; +import { FilesChangerTest } from "./services/files_change_notifier_service_test"; +import { TriggerServiceTest } from "./services/trigger_service_test"; +import { StackServiceTest } from "./services/stack_service_test"; +import mongoose from "mongoose"; +import { CreateDataBaseModelUseCaseTest } from "./usecases/create_database_model_usecase_test"; +import { DeleteDataBaseModelUseCaseTest } from "./usecases/delete_database_model_usecase_test"; +import { ReadDataBaseModelUseCaseTest } from "./usecases/read_database_model_usecase_test"; +import { UpdateDataBaseModelUseCaseTest } from "./usecases/update_database_model_usecase"; +import { PaginationDataBaseModelUseCaseTest } from "./usecases/pagination_database_model_usecase_test"; + const testCore = TestCore.instance; -const __filename: string = fileURLToPath(import.meta.url); - + export const dirname__: string = dirname(__filename); export const assert = testCore.assert; export const resultTest = testCore.resultTest; @@ -19,11 +23,29 @@ const env = new UnitTestEnv(dirname__); locator(env); -const main = async () => { +const tests = [CreateDataBaseModelUseCaseTest, DeleteDataBaseModelUseCaseTest,ReadDataBaseModelUseCaseTest,UpdateDataBaseModelUseCaseTest, PaginationDataBaseModelUseCaseTest] +const init = async () =>{ + await mongoose.connect('mongodb://127.0.0.1:27017/test') +} + +const test = async () =>{ await new ExecutorProgramServiceTest(dirname__).test(); await new FilesChangerTest(dirname__).test(); await new StackServiceTest(dirname__ + "/context/").test(); await new TriggerServiceTest().test(); + await new CreateDataBaseModelUseCaseTest().test() + + await new CreateDataBaseModelUseCaseTest().test() + await new DeleteDataBaseModelUseCaseTest().test() + await new ReadDataBaseModelUseCaseTest().test() + await new UpdateDataBaseModelUseCaseTest().test() + for await (const usecase of tests) { + testCore.assert(await new usecase().test(), usecase.name) + } +} +const main = async () => { + await init() + await test() await testCore.testResult(); }; diff --git a/server/test/usecases/create_database_model_usecase_test.ts b/server/test/usecases/create_database_model_usecase_test.ts new file mode 100644 index 0000000..735d31f --- /dev/null +++ b/server/test/usecases/create_database_model_usecase_test.ts @@ -0,0 +1,12 @@ +import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase"; +import { ITestModel, TestDBModel } from "../model/test_db_mongo_model"; + +export class CreateDataBaseModelUseCaseTest { + async test() { + return ( + await new CreateDataBaseModelUseCase(TestDBModel).call({ + result: "test", + }) + ).isSuccess(); + } +} diff --git a/server/test/usecases/delete_database_model_usecase_test.ts b/server/test/usecases/delete_database_model_usecase_test.ts new file mode 100644 index 0000000..e9809cf --- /dev/null +++ b/server/test/usecases/delete_database_model_usecase_test.ts @@ -0,0 +1,29 @@ +import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase"; +import { DeleteDataBaseModelUseCase } from "../../src/core/usecases/delete_database_model_usecase"; +import { ITestModel, TestDBModel } from "../model/test_db_mongo_model"; + +export class DeleteDataBaseModelUseCaseTest { + async test() { + let testIsSuccess = false; + + const result = await new CreateDataBaseModelUseCase(TestDBModel).call({ + result: "test", + }); + + await result.fold( + async (s) => { + (await new DeleteDataBaseModelUseCase(TestDBModel).call(s.id)).fold( + (_s1) => { + testIsSuccess = true; + }, + (_e1) => {} + ); + }, + async (_e) => { + return; + } + ); + + return testIsSuccess; + } +} diff --git a/server/test/usecases/pagination_database_model_usecase_test.ts b/server/test/usecases/pagination_database_model_usecase_test.ts new file mode 100644 index 0000000..48f3433 --- /dev/null +++ b/server/test/usecases/pagination_database_model_usecase_test.ts @@ -0,0 +1,19 @@ +import { PaginationDataBaseModelUseCase } from "../../src/core/usecases/pagination_database_model_usecase"; +import { ITestModel, TestDBModel } from "../model/test_db_mongo_model"; + +export class PaginationDataBaseModelUseCaseTest { + async test() { + let testIsSuccess = false; + await ( + await new PaginationDataBaseModelUseCase(TestDBModel, 1).call( + 1 + ) + ).fold( + (s) => { + testIsSuccess = s.length === 1; + }, + (_e) => {} + ); + return testIsSuccess; + } +} diff --git a/server/test/usecases/read_database_model_usecase_test.ts b/server/test/usecases/read_database_model_usecase_test.ts new file mode 100644 index 0000000..94fae6e --- /dev/null +++ b/server/test/usecases/read_database_model_usecase_test.ts @@ -0,0 +1,32 @@ +import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase"; +import { ReadByIdDataBaseModelUseCase } from "../../src/core/usecases/read_database_model_usecase"; +import { ITestModel, TestDBModel } from "../model/test_db_mongo_model"; + +export class ReadDataBaseModelUseCaseTest { + async test() { + let testIsSuccess = false; + + const result = await new CreateDataBaseModelUseCase( + TestDBModel + ).call({ + result: "test", + }); + await result.fold( + async (s) => { + const r = await new ReadByIdDataBaseModelUseCase( + TestDBModel + ).call(s.id); + await r.fold( + (_s1) => { + testIsSuccess = true; + + }, + (_e) => {} + ); + }, + async (_e) => {} + ); + + return testIsSuccess; + } +} diff --git a/server/test/usecases/update_database_model_usecase.ts b/server/test/usecases/update_database_model_usecase.ts new file mode 100644 index 0000000..868fec4 --- /dev/null +++ b/server/test/usecases/update_database_model_usecase.ts @@ -0,0 +1,35 @@ +import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase"; +import { UpdateDataBaseModelUseCase } from "../../src/core/usecases/update_database_model_usecase"; +import { ITestModel, TestDBModel } from "../model/test_db_mongo_model"; + +export class UpdateDataBaseModelUseCaseTest { + async test() { + let testIsSuccess = false; + + const model = await new CreateDataBaseModelUseCase( + TestDBModel + ).call({ + result: "test", + }); + await model.fold( + async (s) => { + ( + await new UpdateDataBaseModelUseCase( + TestDBModel + ).call({ + _id:s.id, + result: "complete", + }) + ).fold( + (s1) => { + testIsSuccess = s1.result === "complete"; + }, + (_e1) => {} + ); + }, + async (_e) => {} + ); + + return testIsSuccess; + } +} diff --git a/server/tsconfig.json b/server/tsconfig.json index 33bce8f..f5e853d 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -1,25 +1,19 @@ { + "compileOnSave": false, "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "removeComments": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": [ - "esnext", - "dom" - ], - "moduleResolution":"node", - "sourceMap": true, - "noImplicitReturns": true, - "noUnusedParameters": true, - "pretty": true, - "strict": true, - "skipLibCheck": true, - "noImplicitAny": false - // "moduleResolution": "node" - }, - // "include": ["src/**/*.ts", "src/**/*.json", ".env"], - // "exclude": ["node_modules"] - -} \ No newline at end of file + "target": "es2017", + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "pretty": true, + "declaration": true, + "outDir": "./build", + "allowJs": true, + "noEmit": false, + "esModuleInterop": true, + "resolveJsonModule": true, + "importHelpers": true, + } + } \ No newline at end of file