11import { DMMF } from "@prisma/client/runtime/client" ;
2- import { formatSchema , getDMMF , mergeSchemas } from "@prisma/internals" ;
3- import { MultipleSchemas } from "@prisma/internals/dist/utils/schemaFileInput" ;
42import { Prisma } from "@prisma/sdk" ;
5- import fs from "fs" ;
6- import { HashMap , Singleton , hash , ranges } from "tstl" ;
7- import typia from "typia" ;
83
94import { IRecordMerge } from "@ORGANIZATION/PROJECT-api/lib/structures/common/IRecordMerge" ;
105
11- import { MyConfiguration } from "../../MyConfiguration" ;
126import { MyGlobal } from "../../MyGlobal" ;
7+ import { EntityUtil } from "../../utils/EntityUtil" ;
138import { ErrorProvider } from "./ErrorProvider" ;
149
1510export namespace EntityMergeProvider {
@@ -20,7 +15,7 @@ export namespace EntityMergeProvider {
2015 ) =>
2116 async ( input : IRecordMerge ) : Promise < void > => {
2217 // VALIDATE TABLE
23- const dmmf = await metadata . get ( ) ;
18+ const dmmf = await EntityUtil . getMetadata ( ) ;
2419 const primary : DMMF . Field | undefined = dmmf . datamodel . models
2520 . find ( ( model ) => model . name === table )
2621 ?. fields . find ( ( field ) => field . isId === true ) ;
@@ -43,170 +38,6 @@ export namespace EntityMergeProvider {
4338 } ) ;
4439
4540 // DO MERGE
46- await merge ( table ) ( input ) ;
41+ await EntityUtil . merge ( table ) ( input ) ;
4742 } ;
4843}
49-
50- const metadata = new Singleton ( async ( ) => {
51- const multipleSchemas : MultipleSchemas = await formatSchema ( {
52- schemas : await fs . promises
53- . readdir ( `${ MyConfiguration . ROOT } /prisma/schemas` )
54- . then (
55- async ( files ) =>
56- await Promise . all (
57- files . map (
58- async ( f ) =>
59- [
60- f ,
61- await fs . promises . readFile (
62- `${ MyConfiguration . ROOT } /prisma/schemas/${ f } ` ,
63- "utf8" ,
64- ) ,
65- ] as const ,
66- ) ,
67- ) ,
68- ) ,
69- } ) ;
70- return await getDMMF ( {
71- datamodel : mergeSchemas ( { schemas : multipleSchemas } ) ,
72- } ) ;
73- } ) ;
74-
75- const merge =
76- < Table extends Prisma . ModelName > ( table : Table ) =>
77- async ( props : IRecordMerge ) : Promise < void > => {
78- // FIND TARGET MODEL AND PRIMARY KEY
79- const dmmf = await metadata . get ( ) ;
80- const model : DMMF . Model | undefined = dmmf . datamodel . models . find (
81- ( model ) => model . name === table ,
82- ) ;
83- if ( model === undefined )
84- throw new Error (
85- `Error on EntityUtil.unify(): table ${ table } does not exist.` ,
86- ) ;
87- const key : DMMF . Field | undefined = model . fields . find (
88- ( field ) => field . isId === true ,
89- ) ;
90- if ( key === undefined )
91- throw new Error (
92- `Error on EntityUtil.unify(): table ${ table } does not have single columned primary key.` ,
93- ) ;
94-
95- // LIST UP DEPENDENCIES
96- const dependencies : DMMF . Field [ ] = model . fields . filter (
97- ( field ) =>
98- field . kind === "object" &&
99- typia . is < Prisma . ModelName > ( field . type ) &&
100- ! field . relationFromFields ?. length ,
101- ) ;
102- for ( const dep of dependencies ) {
103- // GET TARGET TABLE MODEL AND FOREIGN COLUMN
104- const target : DMMF . Model = dmmf . datamodel . models . find (
105- ( model ) => model . name === dep . type ,
106- ) ! ;
107- const relation : DMMF . Field = target . fields . find (
108- ( field ) => field . relationName === dep . relationName ,
109- ) ! ;
110- if ( relation . relationFromFields ?. length !== 1 )
111- throw new Error (
112- `Error on EntityUtil.unify(): table ${ getName (
113- target ,
114- ) } has multiple columned foreign key.`,
115- ) ;
116- const foreign : DMMF . Field = target . fields . find (
117- ( f ) => f . name === relation . relationFromFields ! [ 0 ] ,
118- ) ! ;
119-
120- // CONSIDER UNIQUE CONSTRAINT -> CASCADE MERGING
121- const uniqueMatrix : ( readonly string [ ] ) [ ] = target . uniqueFields . filter (
122- ( columns ) => columns . includes ( foreign . name ) ,
123- ) ;
124- if ( uniqueMatrix . length )
125- for ( const unique of uniqueMatrix )
126- await _Merge_unique_children ( {
127- table,
128- ...props ,
129- } ) ( {
130- model : target ,
131- unique,
132- foreign,
133- } ) ;
134- else
135- await ( MyGlobal . prisma as any ) [ getName ( target ) ] . updateMany ( {
136- where : {
137- [ foreign . name ] : { in : props . absorbed } ,
138- } ,
139- data : {
140- [ foreign . name ] : props . keep ,
141- } ,
142- } ) ;
143- }
144-
145- // REMOVE TO BE MERGED RECORD
146- await ( MyGlobal . prisma [ table ] as any ) . deleteMany ( {
147- where : {
148- [ key . name ] : { in : props . absorbed } ,
149- } ,
150- } ) ;
151- } ;
152-
153- const _Merge_unique_children =
154- ( parent : IRecordMerge & { table : Prisma . ModelName } ) =>
155- async ( current : {
156- model : DMMF . Model ;
157- foreign : DMMF . Field ;
158- unique : readonly string [ ] ;
159- } ) => {
160- // GET PRIMARY KEY AND OTHER UNIQUE COLUMNS
161- const primary : DMMF . Field = current . model . fields . find (
162- ( column ) => column . isId === true ,
163- ) ! ;
164- const group : string [ ] = current . unique . filter (
165- ( column ) => column !== current . foreign . name ,
166- ) ;
167-
168- // COMPOSE GROUPS OF OTHER UNIQUE COLUMNS
169- const dict : HashMap < any [ ] , any [ ] > = new HashMap (
170- ( elements ) => hash ( ...elements . map ( ( e ) => JSON . stringify ( e ) ) ) ,
171- ( x , y ) =>
172- ranges . equal ( x , y , ( a , b ) => JSON . stringify ( a ) === JSON . stringify ( b ) ) ,
173- ) ;
174- const recordList : any [ ] = await ( MyGlobal . prisma as any ) [
175- current . model . name
176- ] . findMany ( {
177- where : {
178- [ current . foreign . name ] : {
179- in : [ parent . keep , ...parent . absorbed ] ,
180- } ,
181- } ,
182- orderBy : [
183- {
184- [ primary . name ] : "asc" ,
185- } ,
186- ] ,
187- } ) ;
188- for ( const record of recordList ) {
189- const key : any [ ] = group . map ( ( column ) => record [ column ] ) ;
190- const array : any [ ] = dict . take ( key , ( ) => [ ] ) ;
191- array . push ( record ) ;
192- }
193-
194- // MERGE THEM
195- for ( const it of dict ) {
196- const index : number = it . second . findIndex (
197- ( rec ) => rec [ current . foreign . name ] === parent . keep ,
198- ) ;
199- if ( index === - 1 ) continue ;
200-
201- const master : any = it . second [ index ] ;
202- const slaves : any [ ] = it . second . filter ( ( _r , i ) => i !== index ) ;
203- if ( slaves . length )
204- await merge ( current . model . name as Prisma . ModelName ) ( {
205- keep : master [ primary . name ] ,
206- absorbed : slaves . map ( ( slave ) => slave [ primary . name ] ) ,
207- } ) ;
208- }
209- } ;
210-
211- const getName = ( x : { dbName ?: string | null ; name : string } ) : string =>
212- x . dbName ?? x . name ;
0 commit comments