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 Server from "#framework/server/server";
import getlogger, { defaultLogger } from "#logger";
import {Builder} from "#framework/builder/builder";
const x = Builder<App>(Server);
const app: App = new (class extends App {
public options (setDefinitions: (...definitions: ConfigurationDefinition[]) => void): void {

View File

@ -15,13 +15,15 @@ export class RepoId extends Identifier<string> {
}
}
export default class Repo extends Aggregate<RepoId>{
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<RepoId>{
public get path (): string {
return "/" + this._name;
}
public get userAssignment (): UserAssignment[] {
return this._userAssignment;
}
// public static builder (): IBuilder<Repo> {
// return (<unknown> Builder(Repo)) as IBuilder<Repo>;
// }
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<RepoId> {

View File

@ -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;

View File

@ -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<T> = {
[k in keyof T]-?: (arg: T[k]) => IBuilder<T>
@ -8,19 +10,96 @@ export type IBuilder<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> {
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(
{},
{}
{
// 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>;
}
const builder = Builder<Repo>(Repo);
builder.name("").build();
const ua1 = new UserAssignment(new UserId("test"), UserRight.Read);
const ua2 = new UserAssignment(new UserId("test2"), UserRight.Read);
const builder = Builder<IRepoBuider>(Repo);
const x = builder.id(new RepoId("test")).name("name").addUserAssignment(ua1).addUserAssignment(ua2).build();
console.log(x);