From 5c1525588b3d853df8bd106e2291ffb147938592 Mon Sep 17 00:00:00 2001 From: Joshua Schnabel Date: Mon, 18 Jul 2022 20:57:37 +0200 Subject: [PATCH] add builder --- src/app.ts | 3 + src/application/domain/repo/repo.entity.ts | 23 +++-- .../domain/repo/userAssignment.entity.ts | 4 +- src/framework/builder/builder.ts | 97 +++++++++++++++++-- 4 files changed, 109 insertions(+), 18 deletions(-) diff --git a/src/app.ts b/src/app.ts index 53803cf..88dd1fa 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,6 +7,9 @@ import ConfigurationDefinition, { DefinitionType } from "#configuration/configur import definitionValidators from "#configuration/configurationValidatior"; import Server from "#framework/server/server"; import getlogger, { defaultLogger } from "#logger"; +import {Builder} from "#framework/builder/builder"; + +const x = Builder(Server); const app: App = new (class extends App { public options (setDefinitions: (...definitions: ConfigurationDefinition[]) => void): void { diff --git a/src/application/domain/repo/repo.entity.ts b/src/application/domain/repo/repo.entity.ts index d74a49e..7e8283e 100644 --- a/src/application/domain/repo/repo.entity.ts +++ b/src/application/domain/repo/repo.entity.ts @@ -15,13 +15,15 @@ export class RepoId extends Identifier { } } export default class Repo extends Aggregate{ - + private readonly _id?: RepoId; private _name = ""; + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + private readonly _count = 1; private readonly _userAssignment: UserAssignment[] = []; - - public constructor (id: RepoId| undefined) { + + public constructor (id: RepoId | undefined) { super(); this._id = id; } @@ -41,14 +43,21 @@ export default class Repo extends Aggregate{ public get path (): string { return "/" + this._name; } - + public get userAssignment (): UserAssignment[] { return this._userAssignment; } - // public static builder (): IBuilder { - // return ( Builder(Repo)) as IBuilder; - // } + public addUserAssignment (ua: UserAssignment): UserAssignment[] { + this._userAssignment.push(ua); + return this._userAssignment; + } +} + +export interface IRepoBuider { + name: string; + id: RepoId; + addUserAssignment: UserAssignment; } export class RepoIdGenerator implements IdentifierGenerator { diff --git a/src/application/domain/repo/userAssignment.entity.ts b/src/application/domain/repo/userAssignment.entity.ts index effd681..1c9c6e4 100644 --- a/src/application/domain/repo/userAssignment.entity.ts +++ b/src/application/domain/repo/userAssignment.entity.ts @@ -2,7 +2,7 @@ import { ValueObject } from "#ddd"; import { UserId } from "../user/user.entity"; // import { Builder, IBuilder } from "builder-pattern"; -enum UserRight { +export enum UserRight { Read = "read", AppendOnly = "append", Write = "write" @@ -13,7 +13,7 @@ export class UserAssignment extends ValueObject { private readonly _userId: UserId; - private constructor (userId: UserId, right: UserRight) { + public constructor (userId: UserId, right: UserRight) { super(); this._userId = userId; this._right = right; diff --git a/src/framework/builder/builder.ts b/src/framework/builder/builder.ts index 79756f2..6eca512 100644 --- a/src/framework/builder/builder.ts +++ b/src/framework/builder/builder.ts @@ -1,5 +1,7 @@ -import Repo from "#domain/repo/repo.entity"; -import { reflect } from "typescript-rtti"; +import Repo, { IRepoBuider, RepoId } from "#domain/repo/repo.entity"; +import { UserAssignment, UserRight } from "#domain/repo/userAssignment.entity"; +import { UserId } from "#domain/user/user.entity"; +import { reflect, ReflectedArrayRef, ReflectedClassRef, ReflectedUnionRef } from "typescript-rtti"; export type IBuilder = { [k in keyof T]-?: (arg: T[k]) => IBuilder @@ -8,19 +10,96 @@ export type IBuilder = { build(): T; }; -type Clazz = new(...args: unknown[]) => T; +type Clazz = new (...args: unknown[]) => T; -type Constructor = new (...params: Params) => Result; +type Constructor = new (...params: Params) => Result; + +interface Foo { + [key: string]: unknown; +} export function Builder (type: Constructor): IBuilder { - console.log(reflect(type).class.prototype); + const parameters: { name: string; class: any }[] = []; + const properties = new Map(); + for (const property of reflect(type).properties) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (!property.name.startsWith("_") && property.class.super !== null) { + if (property.type instanceof ReflectedClassRef) { + properties.set(property.name, { name: property.name, class: property.type.class, parameter: false }); + } + else if (property.type instanceof ReflectedUnionRef) { + properties.set(property.name, { name: property.name, class: (>property.type.types.filter(t => t instanceof ReflectedClassRef)[0]).class, parameter: false }); + } + else if (property.type instanceof ReflectedArrayRef) { + properties.set(property.name, { name: property.name, class: (>property.type.elementType).class, aggregation: "array", parameter: false }); + } + } + } + for (const parameter of reflect(type).parameters) { + const name = parameter.rawMetadata.n; + parameters.push({ name: name, class: properties.get(parameter.name) }); + if (properties.get(name) !== undefined) + (properties.get(name) as { parameter: boolean }).parameter = true; + } + + const values = new Map(); const builder = new Proxy( {}, - {} + { + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + get (_target, prop) { + if (typeof prop === "string" && prop.startsWith("add")) { + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + const tprop = prop.charAt(3).toLocaleLowerCase() + prop.substring(4); + return (x: unknown): unknown => { + if (properties.get(tprop)?.aggregation === "array") { + if (!values.has(tprop)) + values.set(tprop, []); + (values.get(tprop) as Array).push(x); + } else { + values.set(tprop, x); + } + return builder; + }; + } else if ("build" === prop) { + const params: unknown[] = []; + for (const param of parameters) { + params.push(values.get(param.name)); + } + const obj: Foo = new type(params); + for (const propertyname of properties.keys()) { + const prop = properties.get(propertyname); + if (values.has(propertyname) && !prop?.parameter) { + if (prop?.aggregation === "array") { + const desc = Object.getOwnPropertyDescriptor(obj, propertyname); + if (desc?.set === undefined) { + const methodeName = "add" + propertyname.charAt(0).toUpperCase() + propertyname.slice(1); + for (const value of (values.get(propertyname) as Array)) { + (obj[methodeName] as ((t: unknown) => unknown))(value); + } + } else { + obj[propertyname] = values.get(propertyname); + } + } else { + obj[propertyname] = values.get(propertyname); + } + } + } + return () => obj; + } + + return (x: unknown): unknown => { + values.set(prop.toString(), x); + return builder; + }; + } + } ); return builder as IBuilder; } - -const builder = Builder(Repo); -builder.name("").build(); \ No newline at end of file +const ua1 = new UserAssignment(new UserId("test"), UserRight.Read); +const ua2 = new UserAssignment(new UserId("test2"), UserRight.Read); +const builder = Builder(Repo); +const x = builder.id(new RepoId("test")).name("name").addUserAssignment(ua1).addUserAssignment(ua2).build(); +console.log(x); \ No newline at end of file