Skip to content
This repository has been archived by the owner on May 18, 2024. It is now read-only.

Commit

Permalink
Close #56 and Close #57
Browse files Browse the repository at this point in the history
  • Loading branch information
samchon committed Mar 6, 2022
1 parent 64dadd8 commit 32c2c99
Show file tree
Hide file tree
Showing 13 changed files with 526 additions and 146 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "safe-typeorm",
"version": "1.0.5",
"version": "1.0.6",
"description": "Safe Relationship Decorators for the TypeORM",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
Expand Down
33 changes: 11 additions & 22 deletions src/builders/AppJoinBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import { SpecialFields } from "../typings/SpecialFields";
import { ReflectAdaptor } from "../decorators/base/ReflectAdaptor";

import { IAppJoinChildTuple } from "./internal/IAppJoinChildTuple";
import { app_join_belongs_many_to_one } from "./internal/app_join_belongs_many_to_one";
import { app_join_belongs_one_to_one } from "./internal/app_join_belongs_one_to_one";
import { app_join_has_many_to_many } from "./internal/app_join_has_many_to_many";
import { app_join_has_one_to_many } from "./internal/app_join_has_one_to_many";
import { app_join_has_one_to_one } from "./internal/app_join_has_one_to_one";
import { get_app_join_function } from "./internal/get_app_join_function";

/**
* Application level join builder.
Expand Down Expand Up @@ -74,8 +70,6 @@ export class AppJoinBuilder<Mine extends object>
*/
public constructor(mine: Creator<Mine>)
{
new Array(3)

this.mine_ = mine;
this.children_ = new Map();
}
Expand Down Expand Up @@ -209,21 +203,16 @@ export class AppJoinBuilder<Mine extends object>
{
for (const [field, child] of this.children_.entries())
{
// JOIN WITH RELATED ENTITIES
let output: Relationship.TargetType<Mine, any>[];
if (child.metadata.type === "Belongs.ManyToOne" || child.metadata.type === "Belongs.External.ManyToOne")
output = await app_join_belongs_many_to_one(this.mine_, child as any, data, field);
else if (child.metadata.type === "Belongs.OneToOne" || child.metadata.type === "Belongs.External.OneToOne")
output = await app_join_belongs_one_to_one(child as any, data, field);
else if (child.metadata.type === "Has.OneToOne" || child.metadata.type === "Has.External.OneToOne")
output = await app_join_has_one_to_one(this.mine_, child as any, data, field);
else if (child.metadata.type === "Has.OneToMany" || child.metadata.type === "Has.External.OneToMany")
output = await app_join_has_one_to_many(this.mine_, child as any, data, field);
else if (child.metadata.type === "Has.ManyToMany")
output = await app_join_has_many_to_many(this.mine_, child as any, data, field);
else
continue;

// CALL APP JOIN FUNCTION
const func: Function = get_app_join_function(child.metadata.type);
const output: Relationship.TargetType<Mine, any>[] = await func
(
this.mine_,
child.metadata,
data,
field
);

// HIERARCHICAL CALL
if (output.length !== 0)
await child.builder._Execute(output);
Expand Down
58 changes: 36 additions & 22 deletions src/builders/internal/app_join_belongs_many_to_one.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,68 @@
import { Belongs } from "../../decorators/Belongs";
import { Creator } from "../../typings/Creator";
import { SpecialFields } from "../../typings/SpecialFields";
import { ITableInfo } from "../../functional/internal/ITableInfo";

import { IAppJoinChildTuple } from "./IAppJoinChildTuple";
import { get_records_by_where_in } from "./get_records_by_where_in";

/**
* @internal
*/
export async function app_join_belongs_many_to_one
export async function app_join_belongs_many_to_one<
Mine extends object,
Target extends object,
Field extends SpecialFields<Mine, Belongs.ManyToOne<Target, any> | Belongs.External.ManyToOne<Target, any>>>
(
mine: Creator<any>,
child: IAppJoinChildTuple<any, Belongs.ManyToOne.IMetadata<any> | Belongs.OneToOne.IMetadata<any>>,
data: any[],
field: any,
): Promise<any[]>
mine: Creator<Mine>,
metadata: Belongs.ManyToOne.IMetadata<Target> | Belongs.External.ManyToOne.IMetadata<Target>,
myData: Mine[],
field: Field,
targetData?: Target[]
): Promise<Target[]>
{
// NO DATA
if (data.length === 0)
if (myData.length === 0)
return [];

// NO REFERENCE
const idList: any[] = data
.map(elem => elem[field].id)
const idList: any[] = myData
.map(elem => (<any>elem[field] as Belongs.ManyToOne<Target, any>).id)
.filter(id => id !== null);
if (idList.length === 0)
return [];

// THE TARGET INFO
const target: Creator<any> = child.metadata.target();
const target: Creator<Target> = metadata.target();
const table: ITableInfo = ITableInfo.get(target);

// LOAD TARGET DATA
const output: any[] = await get_records_by_where_in(target, table.primaryColumn, idList);
const output: Target[]
= targetData
|| await get_records_by_where_in(target, table.primaryColumn, idList);

// LINK RELATIONSHIPS
const dict: Map<any, any> = new Map(output.map(elem => [ elem[table.primaryColumn], elem ]));
for (const elem of data)
const dict: Map<any, any> = new Map(output.map(elem => [ (elem as any)[table.primaryColumn], elem ]));
for (const elem of myData)
{
const id: any | null = elem[field].id;
if (id === null)
const accessor = <any>elem[field] as Belongs.ManyToOne<Target, any>;
if (accessor.id === null)
continue;

const reference: any = dict.get(id)!;
await elem[field].set(reference);
const reference: any = dict.get(accessor.id)!;
await accessor.set(reference);
}

// RECURSIVE
if (target === mine)
await app_join_belongs_many_to_one(mine, child, output, field);

if (<any>target === mine && targetData === undefined)
{
const surplus: Target[] = await app_join_belongs_many_to_one
(
mine,
metadata,
<any>output as Mine[],
field
);
output.push(...surplus);
}
return output;
}
}
60 changes: 41 additions & 19 deletions src/builders/internal/app_join_belongs_one_to_one.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,73 @@
import { Belongs } from "../../decorators/Belongs";
import { Creator } from "../../typings/Creator";
import { SpecialFields } from "../../typings/SpecialFields";
import { ITableInfo } from "../../functional/internal/ITableInfo";

import { IAppJoinChildTuple } from "./IAppJoinChildTuple";
import { get_records_by_where_in } from "./get_records_by_where_in";

/**
* @internal
*/
export async function app_join_belongs_one_to_one
export async function app_join_belongs_one_to_one<
Mine extends object,
Target extends object,
Field extends SpecialFields<Mine, Belongs.OneToOne<Target, any> | Belongs.External.OneToOne<Target, any>>>
(
child: IAppJoinChildTuple<any, Belongs.ManyToOne.IMetadata<any> | Belongs.OneToOne.IMetadata<any>>,
data: any[],
field: any,
): Promise<any[]>
mine: Creator<Mine>,
metadata: Belongs.OneToOne.IMetadata<Target> | Belongs.External.OneToOne.IMetadata<Target>,
myData: Mine[],
field: Field,
targetData?: Target[]
): Promise<Target[]>
{
// NO DATA
if (data.length === 0)
if (myData.length === 0)
return [];

// NO REFERENCE
const idList: any[] = data
.map(elem => elem[field].id)
const idList: any[] = myData
.map(elem => (<any>elem[field] as Belongs.ManyToOne<Target, any>).id)
.filter(id => id !== null);
if (idList.length === 0)
return [];

// THE TARGET INFO
const target: Creator<any> = child.metadata.target();
const target: Creator<Target> = metadata.target();
const table: ITableInfo = ITableInfo.get(target);

// LOAD TARGET DATA
const output: any[] = await get_records_by_where_in(target, table.primaryColumn, idList);
const output: Target[]
= targetData
|| await get_records_by_where_in(target, table.primaryColumn, idList);

// LINK RELATIONSHIPS
const dict: Map<any, any> = new Map(output.map(elem => [ elem[table.primaryColumn], elem ]));
for (const elem of data)
const dict: Map<any, any> = new Map(output.map(elem => [ (elem as any)[table.primaryColumn], elem ]));
for (const elem of myData)
{
const id: any | null = elem[field].id;
if (id === null)
const accessor = <any>elem[field] as Belongs.ManyToOne<Target, any>;
if (accessor.id === null)
continue;

const reference: any = dict.get(id)!;
await elem[field].set(reference);
const reference: any | undefined = dict.get(accessor.id);
if (reference === undefined)
continue;

await accessor.set(reference);
if (metadata.inverse !== null)
await reference[metadata.inverse].set(elem);
}

if (child.metadata.inverse !== null)
await reference[child.metadata.inverse].set(elem);
// RECURSIVE
if (<any>target === mine && targetData === undefined)
{
const surplus: Target[] = await app_join_belongs_one_to_one
(
mine,
metadata,
<any>output as Mine[],
field
);
output.push(...surplus);
}
return output;
}
Loading

0 comments on commit 32c2c99

Please sign in to comment.