@@ -11,7 +11,6 @@ import {
1111 nullableKeyword ,
1212 objectKeyword ,
1313 pluginVersion ,
14- validEnumTypes ,
1514} from "./constants" ;
1615import { JSONSchema4 , JSONSchema4TypeName } from "json-schema" ;
1716import {
@@ -24,13 +23,15 @@ import {
2423 GetColumnQuantifiers ,
2524 getCommentIndexes ,
2625 getDbLabel ,
26+ RemoveNameQuantifiers ,
2727} from "./sharedUtils" ;
2828import {
2929 DatabaseModel ,
3030 ForeignKeyModel ,
3131 PropertyModel ,
3232 TableModel ,
3333} from "@funktechno/sqlsimpleparser/lib/types" ;
34+ import { validJSONSchemaTypes } from "./constants-nosql" ;
3435
3536/**
3637 * convert db to openapi
@@ -58,14 +59,14 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
5859 let schemaKey = key ;
5960 const entity = entities [ key ] ;
6061 let commentIndexes = getCommentIndexes ( key ) ;
61- let description = "" ;
62+ let schemaDescription = "" ;
6263 let formatValue = "" ;
6364 if ( commentIndexes . start > - 1 && commentIndexes . end > - 1 ) {
6465 let result = schemaKey . toString ( ) . trim ( ) ;
6566 commentIndexes = getCommentIndexes ( result ) ;
6667 const firstSpaceIndex = commentIndexes . start ;
6768 const lastSpaceIndex = commentIndexes . end ;
68- schemaKey = result . substring ( 0 , commentIndexes . beforeStart ) ;
69+ schemaKey = result . substring ( 0 , commentIndexes . beforeStart ) . trim ( ) ;
6970 result = result . substring ( firstSpaceIndex , lastSpaceIndex ) . trim ( ) ;
7071 if ( result . indexOf ( formatKeyword ) !== - 1 ) {
7172 const formatIndex = result . indexOf ( formatKeyword ) ;
@@ -75,7 +76,7 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
7576 result = result . substring ( 0 , formatIndex ) ;
7677 }
7778 if ( result ) {
78- description = result ;
79+ schemaDescription = result ;
7980 }
8081 }
8182 if ( schema [ schemaKey ] ) {
@@ -87,8 +88,8 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
8788 additionalProperties : false ,
8889 properties : { } ,
8990 } ;
90- if ( description ) {
91- schema [ schemaKey ] . description = description . trim ( ) ;
91+ if ( schemaDescription ) {
92+ schema [ schemaKey ] . description = schemaDescription . trim ( ) ;
9293 }
9394 if ( formatValue ) {
9495 schema [ schemaKey ] . format = formatValue . trim ( ) ;
@@ -108,26 +109,26 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
108109 const splitPropName = propName . split ( " " ) ;
109110 if (
110111 splitPropName . length == 2 &&
111- validEnumTypes . indexOf ( splitPropName [ 0 ] ) !== - 1 &&
112+ validJSONSchemaTypes . indexOf ( splitPropName [ 0 ] ) !== - 1 &&
112113 splitPropName [ 1 ] == enumKeyword
113114 ) {
114115 isEnum = true ;
115116 type = splitPropName [ 0 ] as JSONSchema4TypeName ;
116117 }
117118 }
118119 // extract desciption /** asdf */
119- let description = "" ;
120+ let propertyDescription = "" ;
120121 let formatValue = "" ;
121122 let enumValues : any [ ] | null = null ;
122123 if (
123124 attribute . attributeType ?. includes ( commentColumnQuantifiers . Start ) &&
124125 attribute . attributeType ?. includes ( commentColumnQuantifiers . End )
125126 ) {
126- let result = attribute . attributeType ;
127- const commentIndexes = getCommentIndexes ( result ) ;
127+ let attributeTypeResult = attribute . attributeType ;
128+ const commentIndexes = getCommentIndexes ( attributeTypeResult ) ;
128129 const firstSpaceIndex = commentIndexes . start ;
129130 const lastSpaceIndex = commentIndexes . end ;
130- const enumRaw = result
131+ const enumRaw = attributeTypeResult
131132 . substring ( 0 , commentIndexes . beforeStart )
132133 . trim ( ) ;
133134 if ( enumRaw ) {
@@ -141,16 +142,16 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
141142 ) ;
142143 }
143144 }
144- result = result . substring ( firstSpaceIndex , lastSpaceIndex ) ;
145- if ( result . indexOf ( formatKeyword ) !== - 1 ) {
146- const formatIndex = result . indexOf ( formatKeyword ) ;
147- formatValue = result
145+ attributeTypeResult = attributeTypeResult . substring ( firstSpaceIndex , lastSpaceIndex ) ;
146+ if ( attributeTypeResult . indexOf ( formatKeyword ) !== - 1 ) {
147+ const formatIndex = attributeTypeResult . indexOf ( formatKeyword ) ;
148+ formatValue = attributeTypeResult
148149 . substring ( formatIndex + formatKeyword . length )
149150 . trim ( ) ;
150- result = result . substring ( 0 , formatIndex ) ;
151+ attributeTypeResult = attributeTypeResult . substring ( 0 , formatIndex ) ;
151152 }
152- if ( result ) {
153- description = result ;
153+ if ( attributeTypeResult . trim ( ) ) {
154+ propertyDescription = attributeTypeResult . trim ( ) ;
154155 }
155156
156157 // decription = attribute.attributeType?.replace("/**", "").replace("*/", "");
@@ -160,24 +161,92 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
160161 if ( enumValues ) {
161162 schema [ schemaKey ] . enum = enumValues ;
162163 }
163- if ( description ) {
164- schema [ schemaKey ] . description = description . trim ( ) ;
164+ if ( propertyDescription . trim ( ) ) {
165+ schema [ schemaKey ] . description = propertyDescription . trim ( ) ;
165166 }
166- if ( formatValue ) {
167+ if ( formatValue . trim ( ) ) {
167168 schema [ schemaKey ] . format = formatValue . trim ( ) ;
168169 }
169170 schema [ schemaKey ] . type = type ;
170171 } else {
172+ // check if type is jsonschema type
173+ let $ref = null ;
174+ let removeType = false ;
175+ let items : JSONSchema4 | null = null ;
176+ let additionalProperties : JSONSchema4 | null = null ;
177+ if ( validJSONSchemaTypes . indexOf ( type ) === - 1 ) {
178+ if ( type . indexOf ( "[]" ) != - 1 ) {
179+ const itemsType = type . replace ( "[]" , "" ) as JSONSchema4TypeName ;
180+ if ( validJSONSchemaTypes . indexOf ( itemsType ) != - 1 ) {
181+ items = {
182+ type : itemsType ,
183+ } ;
184+ type = "array" ;
185+ }
186+ }
187+
188+ if ( validJSONSchemaTypes . indexOf ( type ) != - 1 ) {
189+ //
190+ } else {
191+ // else {
192+ removeType = true ;
193+ $ref = `#/components/schemas/${ RemoveNameQuantifiers ( type ) } ` ;
194+ }
195+ }
196+ if ( [ "array" , "object" ] . indexOf ( type ) !== - 1 ) {
197+ const relationships = db . getRelationships ( ) . filter ( x => x . entityA == key ) ;
198+ const roleLookup = `[${ key } .${ propName } ]` ;
199+ // FIND MATCH
200+ const rel = relationships . find ( x => x . roleA . indexOf ( roleLookup ) != - 1 ) ;
201+ if ( rel ) {
202+ const commentFKIndexes = getCommentIndexes ( rel . entityB ) ;
203+ const entityBName = rel . entityB . substring ( 0 , commentFKIndexes . beforeStart ) . trim ( ) ;
204+ $ref = `#/components/schemas/${ entityBName } ` ;
205+ }
206+ if ( $ref ) {
207+ // if array additionalProperties.$ref
208+ if ( type == "array" ) {
209+ items = {
210+ $ref : $ref
211+ } ;
212+ }
213+ // if object items.$ref
214+ if ( type == "object" ) {
215+ additionalProperties = {
216+ $ref : $ref
217+ } ;
218+ }
219+ }
220+ }
221+
171222 const property : JSONSchema4 = {
172223 title : `${ schemaKey } .${ propName } ` ,
173- nullable : attribute . attributeType ?. includes ( "nullable" ) ?? false ,
174224 type : type ,
175225 } ;
176- if ( description ) {
177- property . description = description . trim ( ) ;
226+ if ( additionalProperties ) {
227+ property . additionalProperties = additionalProperties ;
228+ }
229+ if ( items ) {
230+ property . items = items ;
178231 }
179- if ( formatValue ) {
180- property . format = formatValue . trim ( ) ;
232+ if ( attribute . attributeType ?. includes ( "nullable" ) ) {
233+ property . nullable = true ;
234+ }
235+ if ( $ref && ! additionalProperties ?. $ref && ! items ?. $ref ) {
236+ property [ "$ref" ] = $ref ;
237+ }
238+ if ( removeType ) {
239+ delete property . type ;
240+ }
241+ // $ref properties don't have descriptions
242+ if ( propertyDescription . trim ( ) && ! $ref ) {
243+ // TODO: pull from proper location
244+ property . description = propertyDescription . trim ( ) ;
245+ }
246+ if ( formatValue . trim ( ) ) {
247+ if ( property . items ) {
248+ ( property . items as JSONSchema4 ) . format = formatValue . trim ( ) ;
249+ } else property . format = formatValue . trim ( ) ;
181250 }
182251 schema [ schemaKey ] . properties [ attribute . attributeName ! ] = property ;
183252 }
@@ -191,7 +260,13 @@ export function dbToOpenApi(db: DatabaseModelResult): PartialOpenApiSchema {
191260 return result ;
192261}
193262
194- // TODO: may need to make recursive for when schema property items is array
263+ /**
264+ * used in uml generation
265+ * @param tableName
266+ * @param propertyName
267+ * @param property
268+ * @returns
269+ */
195270export function GeneratePropertyModel (
196271 tableName : string ,
197272 propertyName : string ,
@@ -200,9 +275,12 @@ export function GeneratePropertyModel(
200275 let columnProperties = ( property . type ?? objectKeyword ) . toString ( ) ;
201276 if ( columnProperties === arrayKeyword ) {
202277 if ( property . items && typeof property . items === objectKeyword ) {
203- if ( ( property . items as JSONSchema4 ) . format )
204- columnProperties = `${ ( property . items as JSONSchema4 ) . format } []` ;
205- else if ( ( property . items as JSONSchema4 ) . type )
278+ if ( ( property . items as JSONSchema4 ) . format && ! property . format ) {
279+ property . format = ( property . items as JSONSchema4 ) . format ;
280+ // columnProperties = `${(property.items as JSONSchema4).format}[]`;
281+ }
282+ // else
283+ if ( ( property . items as JSONSchema4 ) . type )
206284 columnProperties = `${ ( property . items as JSONSchema4 ) . type } []` ;
207285 }
208286 }
@@ -225,7 +303,11 @@ export function GeneratePropertyModel(
225303 } ;
226304 return result ;
227305}
228-
306+ /**
307+ * convert openapi schema to database model
308+ * @param schemas
309+ * @returns
310+ */
229311export function ConvertOpenApiToDatabaseModel (
230312 schemas : Record < string , OpenApiSchemaTypeDefinition >
231313) : DatabaseModel {
0 commit comments