1- import { Model , Enum , DataModel } from '@zenstackhq/language/ast' ;
1+ import { Model , Enum , DataModel , DataField } from '@zenstackhq/language/ast' ;
22import { ZModelCodeGenerator } from '@zenstackhq/sdk' ;
33import fs from 'node:fs' ;
44import path from 'node:path' ;
@@ -11,7 +11,7 @@ import {
1111} from './action-utils' ;
1212import { syncEnums , syncRelation , syncTable , type Relation } from './pull' ;
1313import { providers } from './pull/provider' ;
14- import { getDatasource , getDbName } from './pull/utils' ;
14+ import { getDatasource , getDbName , getRelationFkName } from './pull/utils' ;
1515import { config } from '@dotenvx/dotenvx' ;
1616
1717type PushOptions = {
@@ -25,7 +25,7 @@ export type PullOptions = {
2525 out ?: string ;
2626 naming ?: 'pascal' | 'camel' | 'snake' | 'kebab' | 'none' ;
2727 alwaysMap ?: boolean ;
28- excludeSchemas : string [ ] ;
28+ excludeSchemas ? : string [ ] ;
2929} ;
3030
3131/**
@@ -92,8 +92,8 @@ async function runPull(options: PullOptions) {
9292 }
9393
9494 const { enums : allEnums , tables : allTables } = await provider . introspect ( datasource . url ) ;
95- const enums = allEnums . filter ( ( e ) => ! options . excludeSchemas . includes ( e . schema_name ) ) ;
96- const tables = allTables . filter ( ( t ) => ! options . excludeSchemas . includes ( t . schema ) ) ;
95+ const enums = allEnums . filter ( ( e ) => ! options . excludeSchemas ? .includes ( e . schema_name ) ) ;
96+ const tables = allTables . filter ( ( t ) => ! options . excludeSchemas ? .includes ( t . schema ) ) ;
9797
9898 const newModel : Model = {
9999 $type : 'Model' ,
@@ -113,79 +113,178 @@ async function runPull(options: PullOptions) {
113113 }
114114
115115 for ( const relation of resolvedRelations ) {
116- syncRelation ( { model : newModel , relation, services, options } ) ;
116+ const simmilarRelations = resolvedRelations . filter ( ( rr ) => {
117+ return (
118+ ( rr . schema === relation . schema &&
119+ rr . table === relation . table &&
120+ rr . references . schema === relation . references . schema &&
121+ rr . references . table === relation . references . table ) ||
122+ ( rr . schema === relation . references . schema &&
123+ rr . column === relation . references . column &&
124+ rr . references . schema === relation . schema &&
125+ rr . references . table === relation . table )
126+ ) ;
127+ } ) . length ;
128+ const selfRelation =
129+ relation . references . schema === relation . schema && relation . references . table === relation . table ;
130+ syncRelation ( {
131+ model : newModel ,
132+ relation,
133+ services,
134+ options,
135+ selfRelation,
136+ simmilarRelations,
137+ } ) ;
117138 }
118139
119140 const cwd = new URL ( `file://${ process . cwd ( ) } ` ) . pathname ;
120141 const docs = services . shared . workspace . LangiumDocuments . all
121142 . filter ( ( { uri } ) => uri . path . toLowerCase ( ) . startsWith ( cwd . toLowerCase ( ) ) )
122143 . toArray ( ) ;
123144 const docsSet = new Set ( docs . map ( ( d ) => d . uri . toString ( ) ) ) ;
124- console . log ( docsSet ) ;
145+
146+ services . shared . workspace . IndexManager . allElements ( 'DataModel' , docsSet )
147+ . filter (
148+ ( declaration ) =>
149+ ! newModel . declarations . find ( ( d ) => getDbName ( d ) === getDbName ( declaration . node as any ) ) ,
150+ )
151+ . forEach ( ( decl ) => {
152+ const model = decl . node ! . $container as Model ;
153+ const index = model . declarations . findIndex ( ( d ) => d === decl . node ) ;
154+ model . declarations . splice ( index , 1 ) ;
155+ console . log ( `Delete model ${ decl . name } ` ) ;
156+ } ) ;
157+ services . shared . workspace . IndexManager . allElements ( 'Enum' , docsSet )
158+ . filter (
159+ ( declaration ) =>
160+ ! newModel . declarations . find ( ( d ) => getDbName ( d ) === getDbName ( declaration . node as any ) ) ,
161+ )
162+ . forEach ( ( decl ) => {
163+ const model = decl . node ! . $container as Model ;
164+ const index = model . declarations . findIndex ( ( d ) => d === decl . node ) ;
165+ model . declarations . splice ( index , 1 ) ;
166+ console . log ( `Delete enum ${ decl . name } ` ) ;
167+ } ) ;
168+
125169 newModel . declarations
126170 . filter ( ( d ) => [ DataModel , Enum ] . includes ( d . $type ) )
127171 . forEach ( ( _declaration ) => {
128172 const declaration = _declaration as DataModel | Enum ;
129- const declarations = services . shared . workspace . IndexManager . allElements ( declaration . $type , docsSet ) ;
173+ const declarations = services . shared . workspace . IndexManager . allElements (
174+ declaration . $type ,
175+ docsSet ,
176+ ) . toArray ( ) ;
130177 const originalModel = declarations . find ( ( d ) => getDbName ( d . node as any ) === getDbName ( declaration ) )
131178 ?. node as DataModel | Enum | undefined ;
132179 if ( ! originalModel ) {
133180 model . declarations . push ( declaration ) ;
134181 ( declaration as any ) . $container = model ;
182+ declaration . fields . forEach ( ( f ) => {
183+ if ( f . $type === 'DataField' && f . type . reference ?. ref ) {
184+ const ref = declarations . find (
185+ ( d ) => getDbName ( d . node as any ) === getDbName ( f . type . reference ! . ref as any ) ,
186+ ) ?. node ;
187+ if ( ref ) ( f . type . reference . ref as any ) = ref ;
188+ }
189+ } ) ;
135190 return ;
136191 }
137192
138193 declaration . fields . forEach ( ( f ) => {
139- const originalField = originalModel . fields . find ( ( d ) => getDbName ( d ) === getDbName ( f ) ) ;
194+ const originalField = originalModel . fields . find (
195+ ( d ) =>
196+ getDbName ( d ) === getDbName ( f ) ||
197+ ( getRelationFkName ( d as any ) === getRelationFkName ( f as any ) &&
198+ ! ! getRelationFkName ( d as any ) &&
199+ ! ! getRelationFkName ( f as any ) ) ,
200+ ) ;
140201
141202 if ( ! originalField ) {
142- console . log ( `Added field ${ f . name } to ${ originalModel . name } ` ) ;
203+ // console.log(`Added field ${f.name} to ${originalModel.name}`);
143204 ( f as any ) . $container = originalModel ;
144205 originalModel . fields . push ( f as any ) ;
206+ if ( f . $type === 'DataField' && f . type . reference ?. ref ) {
207+ const ref = declarations . find (
208+ ( d ) => getDbName ( d . node as any ) === getDbName ( f . type . reference ! . ref as any ) ,
209+ ) ?. node as DataModel | undefined ;
210+ if ( ref ) {
211+ ( f . type . reference . $refText as any ) = ref . name ;
212+ ( f . type . reference . ref as any ) = ref ;
213+ }
214+ }
145215 return ;
146216 }
147- //TODO: update field
217+
218+ if ( originalField . $type === 'DataField' ) {
219+ const field = f as DataField ;
220+ originalField . type = field . type ;
221+ if ( field . type . reference ) {
222+ const ref = declarations . find (
223+ ( d ) => getDbName ( d . node as any ) === getDbName ( field . type . reference ! . ref as any ) ,
224+ ) ?. node as DataModel | undefined ;
225+ if ( ref ) {
226+ ( field . type . reference . $refText as any ) = ref . name ;
227+ ( field . type . reference . ref as any ) = ref ;
228+ }
229+ }
230+
231+ ( originalField . type . $container as any ) = originalField ;
232+ }
233+
234+ f . attributes . forEach ( ( attr ) => {
235+ const originalAttribute = originalField . attributes . find (
236+ ( d ) => d . decl . $refText === attr . decl . $refText ,
237+ ) ;
238+
239+ if ( ! originalAttribute ) {
240+ //console.log(`Added Attribute ${attr.decl.$refText} to ${f.name}`);
241+ ( f as any ) . $container = originalField ;
242+ originalField . attributes . push ( attr as any ) ;
243+ return ;
244+ }
245+
246+ originalAttribute . args = attr . args ;
247+ attr . args . forEach ( ( a ) => {
248+ ( a . $container as any ) = originalAttribute ;
249+ } ) ;
250+ } ) ;
251+
252+ originalField . attributes
253+ . filter ( ( attr ) => ! f . attributes . find ( ( d ) => d . decl . $refText === attr . decl . $refText ) )
254+ . forEach ( ( attr ) => {
255+ const field = attr . $container ;
256+ const index = field . attributes . findIndex ( ( d ) => d === attr ) ;
257+ field . attributes . splice ( index , 1 ) ;
258+ //console.log(`Delete attribute from field:${field.name} ${attr.decl.$refText}`);
259+ } ) ;
148260 } ) ;
149261 originalModel . fields
150- . filter ( ( f ) => ! declaration . fields . find ( ( d ) => getDbName ( d ) === getDbName ( f ) ) )
262+ . filter (
263+ ( f ) =>
264+ ! declaration . fields . find (
265+ ( d ) =>
266+ getDbName ( d ) === getDbName ( f ) ||
267+ ( getRelationFkName ( d as any ) === getRelationFkName ( f as any ) &&
268+ ! ! getRelationFkName ( d as any ) &&
269+ ! ! getRelationFkName ( f as any ) ) ,
270+ ) ,
271+ )
151272 . forEach ( ( f ) => {
152273 const model = f . $container ;
153274 const index = model . fields . findIndex ( ( d ) => d === f ) ;
154275 model . fields . splice ( index , 1 ) ;
155- console . log ( `Delete field ${ f . name } ` ) ;
276+ // console.log(`Delete field ${f.name}`);
156277 } ) ;
157278 } ) ;
158279
159- services . shared . workspace . IndexManager . allElements ( 'DataModel' , docsSet )
160- . filter (
161- ( declaration ) =>
162- ! newModel . declarations . find ( ( d ) => getDbName ( d ) === getDbName ( declaration . node as any ) ) ,
163- )
164- . forEach ( ( decl ) => {
165- const model = decl . node ! . $container as Model ;
166- const index = model . declarations . findIndex ( ( d ) => d === decl . node ) ;
167- model . declarations . splice ( index , 1 ) ;
168- console . log ( `Delete model ${ decl . name } ` ) ;
169- } ) ;
170- services . shared . workspace . IndexManager . allElements ( 'Enum' , docsSet )
171- . filter (
172- ( declaration ) =>
173- ! newModel . declarations . find ( ( d ) => getDbName ( d ) === getDbName ( declaration . node as any ) ) ,
174- )
175- . forEach ( ( decl ) => {
176- const model = decl . node ! . $container as Model ;
177- const index = model . declarations . findIndex ( ( d ) => d === decl . node ) ;
178- model . declarations . splice ( index , 1 ) ;
179- console . log ( `Delete enum ${ decl . name } ` ) ;
180- } ) ;
181-
182280 if ( options . out && ! fs . lstatSync ( options . out ) . isFile ( ) ) {
183281 throw new Error ( `Output path ${ options . out } is not a file` ) ;
184282 }
185283
186284 const generator = new ZModelCodeGenerator ( {
187285 //TODO: make configurable
188286 quote : 'double' ,
287+ indent : 2 ,
189288 } ) ;
190289
191290 if ( options . out ) {
0 commit comments