add builder

This commit is contained in:
2022-07-18 20:57:37 +02:00
parent 3597548b4d
commit 5c1525588b
4 changed files with 109 additions and 18 deletions

View File

@ -7,6 +7,9 @@ import ConfigurationDefinition, { DefinitionType } from "#configuration/configur
import definitionValidators from "#configuration/configurationValidatior"; import definitionValidators from "#configuration/configurationValidatior";
import Server from "#framework/server/server"; import Server from "#framework/server/server";
import getlogger, { defaultLogger } from "#logger"; import getlogger, { defaultLogger } from "#logger";
import {Builder} from "#framework/builder/builder";
const x = Builder<App>(Server);
const app: App = new (class extends App { const app: App = new (class extends App {
public options (setDefinitions: (...definitions: ConfigurationDefinition[]) => void): void { public options (setDefinitions: (...definitions: ConfigurationDefinition[]) => void): void {

View File

@ -18,10 +18,12 @@ export default class Repo extends Aggregate<RepoId>{
private readonly _id?: RepoId; private readonly _id?: RepoId;
private _name = ""; private _name = "";
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
private readonly _count = 1;
private readonly _userAssignment: UserAssignment[] = []; private readonly _userAssignment: UserAssignment[] = [];
public constructor (id: RepoId| undefined) { public constructor (id: RepoId | undefined) {
super(); super();
this._id = id; this._id = id;
} }
@ -46,9 +48,16 @@ export default class Repo extends Aggregate<RepoId>{
return this._userAssignment; return this._userAssignment;
} }
// public static builder (): IBuilder<Repo> { public addUserAssignment (ua: UserAssignment): UserAssignment[] {
// return (<unknown> Builder(Repo)) as IBuilder<Repo>; this._userAssignment.push(ua);
// } return this._userAssignment;
}
}
export interface IRepoBuider {
name: string;
id: RepoId;
addUserAssignment: UserAssignment;
} }
export class RepoIdGenerator implements IdentifierGenerator<RepoId> { export class RepoIdGenerator implements IdentifierGenerator<RepoId> {

View File

@ -2,7 +2,7 @@ import { ValueObject } from "#ddd";
import { UserId } from "../user/user.entity"; import { UserId } from "../user/user.entity";
// import { Builder, IBuilder } from "builder-pattern"; // import { Builder, IBuilder } from "builder-pattern";
enum UserRight { export enum UserRight {
Read = "read", Read = "read",
AppendOnly = "append", AppendOnly = "append",
Write = "write" Write = "write"
@ -13,7 +13,7 @@ export class UserAssignment extends ValueObject {
private readonly _userId: UserId; private readonly _userId: UserId;
private constructor (userId: UserId, right: UserRight) { public constructor (userId: UserId, right: UserRight) {
super(); super();
this._userId = userId; this._userId = userId;
this._right = right; this._right = right;

View File

@ -1,5 +1,7 @@
import Repo from "#domain/repo/repo.entity"; import Repo, { IRepoBuider, RepoId } from "#domain/repo/repo.entity";
import { reflect } from "typescript-rtti"; 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<T> = { export type IBuilder<T> = {
[k in keyof T]-?: (arg: T[k]) => IBuilder<T> [k in keyof T]-?: (arg: T[k]) => IBuilder<T>
@ -8,19 +10,96 @@ export type IBuilder<T> = {
build(): T; build(): T;
}; };
type Clazz<T> = new(...args: unknown[]) => T; type Clazz<T> = new (...args: unknown[]) => T;
type Constructor<Params extends readonly any[] = readonly any[], Result = any> = new (...params: Params) => Result; type Constructor<Params extends readonly any[] = readonly any[], Result = any> = new (...params: Params) => Result;
interface Foo {
[key: string]: unknown;
}
export function Builder<Type> (type: Constructor): IBuilder<Type> { export function Builder<Type> (type: Constructor): IBuilder<Type> {
console.log(reflect(type).class.prototype); const parameters: { name: string; class: any }[] = [];
const properties = new Map<string, { name: string; class: any, aggregation?: string, parameter: boolean }>();
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: (<ReflectedClassRef<unknown>>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: (<ReflectedClassRef<unknown>>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<string, unknown>();
const builder = new Proxy( 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<unknown>).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<unknown>)) {
(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<Type>; return builder as IBuilder<Type>;
} }
const ua1 = new UserAssignment(new UserId("test"), UserRight.Read);
const builder = Builder<Repo>(Repo); const ua2 = new UserAssignment(new UserId("test2"), UserRight.Read);
builder.name("").build(); const builder = Builder<IRepoBuider>(Repo);
const x = builder.id(new RepoId("test")).name("name").addUserAssignment(ua1).addUserAssignment(ua2).build();
console.log(x);