@@ -25,49 +25,83 @@ export namespace TransactionBuilder {
2525
2626 class TreeMapperBuilder < T = any > {
2727 private readonly _entryType : Constructor < T > ;
28- private _jsonData : IObjectLiteral < any > [ ] ;
28+ private _root : IObjectLiteral < any > [ ] ;
2929 private _resource = new Map < string , IObjectLiteral < any > > ( ) ;
3030
3131 constructor ( type : Constructor < T > ) {
3232 this . _entryType = type ;
3333 }
3434
35- addJsonData ( data : IObjectLiteral < any > | IObjectLiteral < any > [ ] ) : TreeMapperBuilder < T > {
36- this . _jsonData = Array . isArray ( data ) ? data : [ data ] ;
35+ setRoot ( data : IObjectLiteral < any > | IObjectLiteral < any > [ ] ) : TreeMapperBuilder < T > {
36+ if ( ! Array . isArray ( data ) && Private . isNode ( data ) ) {
37+ this . _root = [ data ] ;
38+ } else {
39+ if ( Private . isAllNodes ( data as IObjectLiteral < any > [ ] ) ) {
40+ this . _root = data as IObjectLiteral < any > [ ] ;
41+ }
42+ }
43+
44+ this . addJsonData ( data ) ;
3745 return this ;
3846 }
3947
4048 /**
4149 * Walk the resource graph and add all nodes into resource cache by its `uid`.
4250 */
43- addResourceData ( data : IObjectLiteral < any > | IObjectLiteral < any > [ ] ) : TreeMapperBuilder < T > {
51+ addJsonData ( data : IObjectLiteral < any > | IObjectLiteral < any > [ ] ) : TreeMapperBuilder < T > {
4452 if ( data && ! ( data instanceof Array ) && data . uid ) {
45- this . _resource . set ( data . uid , data ) ;
53+ const { obj, predicates } = Private . separatePredicates ( data ) ;
54+
55+ if ( this . _resource . has ( obj . uid ) ) {
56+ const existingObj = this . _resource . get ( obj . uid ) as IObjectLiteral < any > ;
57+ // trying to not modify existing object ref
58+ Object . assign ( existingObj , obj ) ;
59+ } else {
60+ this . _resource . set ( obj . uid , obj ) ;
61+ }
62+
63+ for ( const key of predicates . keys ( ) ) {
64+ const predicate = predicates . get ( key ) as IObjectLiteral < any > [ ] ;
65+ // store nodes from the predicate
66+ this . addJsonData ( predicate ) ;
67+ const existingObj = this . _resource . get ( obj . uid ) as IObjectLiteral < any > ;
68+ const pred = existingObj [ key ] as IObjectLiteral < any > [ ] ;
69+
70+ predicate . forEach ( p => {
71+ const pObj = this . _resource . get ( p . uid ) as IObjectLiteral < any > ;
72+
73+ if ( pred . indexOf ( pObj ) > - 1 ) {
74+ return ;
75+ }
76+
77+ pred . push ( pObj ) ;
78+ } ) ;
79+ }
80+
4681 return this ;
4782 }
4883
4984 data . forEach ( ( d : any ) => {
50- this . addResourceData ( d ) ;
85+ this . addJsonData ( d ) ;
5186 } ) ;
5287
5388 return this ;
5489 }
5590
5691 build ( ) : ITransaction < T > {
57- // Do not traverse the json tree if there is no
58- // resource data.
59- if ( this . _resource . size > 0 ) {
60- const visited = new Set < string > ( ) ;
61- Array . isArray ( this . _jsonData )
62- ? this . _jsonData . map ( jd => Private . expand ( visited , this . _resource , jd ) )
63- : Private . expand ( visited , this . _resource , this . _jsonData ) ;
64- }
65-
66- if ( ! Array . isArray ( this . _jsonData ) ) {
67- this . _jsonData = [ this . _jsonData ] ;
68- }
69-
70- return new Transaction ( this . _entryType , this . _jsonData ) ;
92+ // eslint-disable-next-line @typescript-eslint/no-var-requires
93+ // const util = require('util');
94+ // console.log(
95+ // util.inspect(
96+ // this._root.map(o => this._resource.get(o.uid)),
97+ // { colors: true, depth: 20 }
98+ // )
99+ // );
100+
101+ return new Transaction (
102+ this . _entryType ,
103+ this . _root . map ( o => this . _resource . get ( o . uid ) )
104+ ) ;
71105 }
72106 }
73107}
@@ -76,35 +110,31 @@ export namespace TransactionBuilder {
76110 * Module private statics
77111 */
78112namespace Private {
79- /**
80- * Visit all nodes in a tree recursively, matching node uid in the resource data and adding extra information.
81- *
82- * ### NOTE
83- * Expand will modify the data in-place.
84- */
85- export function expand ( visited : Set < string > , resource : IObjectLiteral < any > , source : IObjectLiteral < any > ) : void {
86- if ( resource . has ( source . uid ) ) {
87- Object . assign ( source , resource . get ( source . uid ) ) ;
88- }
113+ export function separatePredicates (
114+ obj : IObjectLiteral < any >
115+ ) : { obj : IObjectLiteral < any > ; predicates : Map < string , IObjectLiteral < any > [ ] > } {
116+ const predicates : Map < string , IObjectLiteral < any > [ ] > = new Map ( ) ;
89117
90- Object . keys ( source ) . forEach ( key => {
91- if ( key === 'dgraph.type' ) {
92- return ;
93- }
118+ Object . keys ( obj ) . forEach ( ( key : string ) => {
119+ if ( isPredicate ( obj , key ) ) {
120+ predicates . set ( key , obj [ key ] ) ;
94121
95- if ( ! Array . isArray ( source [ key ] ) ) {
96- return ;
122+ obj [ key ] = [ ] ;
97123 }
124+ } ) ;
98125
99- source [ key ] . forEach ( ( node : any ) => {
100- const visitingKey = `${ source . uid } :${ key } :${ node . uid } ` ;
101- if ( visited . has ( visitingKey ) ) {
102- return ;
103- }
126+ return { obj, predicates } ;
127+ }
104128
105- visited . add ( visitingKey ) ;
106- return expand ( visited , resource , node ) ;
107- } ) ;
108- } ) ;
129+ export function isPredicate ( obj : IObjectLiteral < any > , key : string ) : boolean {
130+ return isAllNodes ( obj [ key ] ) ;
131+ }
132+
133+ export function isAllNodes ( obj : IObjectLiteral < any > [ ] ) : boolean {
134+ return Array . isArray ( obj ) && ( obj as Array < any > ) . every ( isNode ) ;
135+ }
136+
137+ export function isNode ( obj : IObjectLiteral < any > ) : boolean {
138+ return ! ! obj . uid ;
109139 }
110140}
0 commit comments