@@ -7,7 +7,7 @@ import DI from '../di';
77import Entities from '../entities' ;
88
99
10- export class MakeDbViewCommand extends Command {
10+ export class MakeDbView extends Command {
1111 static getName ( ) {
1212 return 'make:dbview' ;
1313 }
@@ -68,7 +68,7 @@ CREATE ALGORITHM=UNDEFINED SQL SECURITY DEFINER VIEW view_${tableName}
6868 }
6969}
7070
71- export class MakeEntityCommand extends Command {
71+ export class MakeEntity extends Command {
7272 static getName ( ) {
7373 return 'make:entity' ;
7474 }
@@ -175,7 +175,6 @@ export class MakeEntityCommand extends Command {
175175
176176 static typeAdditional ( _type , sequlizeType , rawColumn ) {
177177 const type = _type . toLowerCase ( ) ;
178- // console.log(_type, sequlizeType)
179178 let finalType = sequlizeType ;
180179
181180 if ( type . match ( / u n s i g n e d / ) ) {
@@ -253,17 +252,17 @@ export class MakeEntityCommand extends Command {
253252 } ) ;
254253 Object . values ( rawColumns ) . forEach ( ( rawColumn ) => {
255254 const columnName = rawColumn . Field ;
256- columns [ columnName ] . type = MakeEntityCommand . typeAdditional (
255+ columns [ columnName ] . type = MakeEntity . typeAdditional (
257256 columns [ columnName ] . type ,
258- MakeEntityCommand . typeMapping ( columns [ columnName ] . type ) ,
257+ MakeEntity . typeMapping ( columns [ columnName ] . type ) ,
259258 rawColumn
260259 ) ;
261260 columns [ columnName ] . unique = rawColumn . Key === 'UNI' ;
262261 columns [ columnName ] . comment = rawColumn . Comment ;
263262 columns [ columnName ] . autoIncrement = rawColumn . Extra . startsWith ( 'auto_increment' ) === true ;
264263 } ) ;
265264
266- const indexes = await MakeEntityCommand . getIndexes ( table , sequelize ) ;
265+ const indexes = await MakeEntity . getIndexes ( table , sequelize ) ;
267266 const entityFile = `${ path } /${ table } .js` ;
268267 const schemaFile = `${ schemaPath } /${ table } .js` ;
269268 try {
@@ -289,7 +288,203 @@ export class MakeEntityCommand extends Command {
289288 } ;
290289
291290 //Skip sequelize migrate table
292- await Promise . all ( Object . values ( tables ) . filter ( t => t !== 'sequelizemeta' ) . map ( tableHandler ) ) ;
291+ await Promise . all ( Object . values ( tables ) . filter ( t => ! [ 'sequelizemeta' , 'tramp_migrations' ] . includes ( t ) ) . map ( tableHandler ) ) ;
292+ logger . info ( 'All DB schemas generated' ) ;
293+ }
294+ }
295+
296+ export class MakeGraphql extends Command {
297+ static getName ( ) {
298+ return 'make:graphql' ;
299+ }
300+
301+ static getDescription ( ) {
302+ return 'Generate graphql schema' ;
303+ }
304+
305+ static getSpec ( ) {
306+ return {
307+ dir : {
308+ required : false ,
309+ description : 'Where entity files to be generated'
310+ } ,
311+ prefix : {
312+ required : false ,
313+ description : 'Table prefix'
314+ } ,
315+ mapping : {
316+ required : false ,
317+ description : 'Mapping file path'
318+ }
319+ } ;
320+ }
321+
322+ static typeMapping ( _type ) {
323+ const type = _type . toLowerCase ( ) ;
324+ if ( type === 'tinyint(1)' || type === 'boolean' || type === 'bit(1)' ) {
325+ return 'Boolean' ;
326+ }
327+
328+ if ( type . match ( / ^ ( s m a l l i n t | m e d i u m i n t | t i n y i n t | i n t ) / ) ) {
329+ return 'Int' ;
330+ }
331+
332+ if ( type . startsWith ( 'bigint' ) ) {
333+ return 'Int' ;
334+ }
335+
336+ if ( type . startsWith ( 'enum' ) ) {
337+ return 'Enum' ;
338+ }
339+
340+ if ( type . match ( / ^ s t r i n g | v a r c h a r | v a r y i n g | n v a r c h a r / ) ) {
341+ return 'String' ;
342+ }
343+
344+ if ( type . startsWith ( 'char' ) ) {
345+ return 'String' ;
346+ }
347+
348+ if ( type . match ( / t e x t | n t e x t $ / ) ) {
349+ return 'String' ;
350+ }
351+
352+ if ( type . startsWith ( 'year' ) ) {
353+ return 'Int' ;
354+ }
355+
356+ if ( type . startsWith ( 'datetime' ) ) {
357+ return 'String' ;
358+ }
359+
360+ if ( type . startsWith ( 'date' ) ) {
361+ return 'String' ;
362+ }
363+
364+ if ( type . startsWith ( 'time' ) ) {
365+ return 'String' ;
366+ }
367+
368+ if ( type . match ( / ^ ( f l o a t 8 | d o u b l e p r e c i s i o n ) / ) ) {
369+ return 'Float' ;
370+ }
371+
372+ if ( type . match ( / ^ ( f l o a t | f l o a t 4 ) / ) ) {
373+ return 'Float' ;
374+ }
375+
376+ if ( type . startsWith ( 'decimal' ) ) {
377+ return 'Float' ;
378+ }
379+
380+ if ( type . match ( / ^ u u i d | u n i q u e i d e n t i f i e r / ) ) {
381+ return 'String' ;
382+ }
383+
384+ if ( type . startsWith ( 'jsonb' ) ) {
385+ return 'JSON' ;
386+ }
387+ if ( type . startsWith ( 'json' ) ) {
388+ return 'JSON' ;
389+ }
390+
391+ if ( type . startsWith ( 'geometry' ) ) {
392+ return 'String' ;
393+ }
394+
395+ return type ;
396+ }
397+
398+ getEnums ( _type , columnName , tableName ) {
399+ const type = _type . toLowerCase ( ) ;
400+ const values = type . slice ( 5 , - 1 ) . split ( ',' ) . map ( v => v . slice ( 1 , - 1 ) ) ;
401+ return {
402+ name : `ENUM_${ tableName } _${ columnName } ` ,
403+ values
404+ } ;
405+ }
406+
407+ async run ( ) {
408+ const config = DI . get ( 'config' ) . get ( ) ;
409+ const logger = DI . get ( 'logger' ) ;
410+ const sequelize = new Sequelize (
411+ config . db . database ,
412+ null ,
413+ null ,
414+ Object . assign ( { } , config . sequelize , config . db , { logging : logger . getInstance ( ) . verbose } )
415+ ) ;
416+ const query = sequelize . getQueryInterface ( ) ;
417+
418+ let tables = await query . showAllTables ( ) ;
419+ const views = await sequelize . query ( `SHOW FULL TABLES IN ${ config . db . database } WHERE TABLE_TYPE LIKE 'VIEW'` , {
420+ type : sequelize . QueryTypes . SELECT ,
421+ raw : true
422+ } ) ;
423+ if ( views ) {
424+ const viewNames = views . map ( v => Object . values ( v ) [ 0 ] ) ;
425+ tables = tables . filter ( t => ! viewNames . includes ( t ) ) ;
426+ }
427+ const {
428+ dir, prefix, mapping
429+ } = this . getArgv ( ) ;
430+ if ( prefix ) {
431+ tables = tables . filter ( t => t . startsWith ( prefix ) ) ;
432+ }
433+
434+ const path = dir ? `${ process . cwd ( ) } /${ dir } ` : `${ process . cwd ( ) } /src/graphql` ;
435+ const schemaPath = `${ path } /entities` ;
436+ const schemaTemplate = fs . readFileSync ( `${ __dirname } /../../template/graphql.ejs` , 'utf8' ) ;
437+ const mappingFile = mapping ? `${ process . cwd ( ) } /${ mapping } ` : `${ process . cwd ( ) } /src/graphql/mapping.json` ;
438+ const mappingContent = JSON . parse ( fs . readFileSync ( mappingFile , 'utf8' ) ) ;
439+ const getMappedTableName = tableName =>
440+ ( mappingContent [ tableName ] ? mappingContent [ tableName ] : tableName ) ;
441+ mkdirp . sync ( path ) ;
442+ mkdirp . sync ( schemaPath ) ;
443+
444+ logger . info ( 'Start generate GraphQL schemas to dir %s' , path ) ;
445+
446+ const tableHandler = async ( tableName ) => {
447+ const enums = [ ] ;
448+ const columns = await query . describeTable ( tableName ) ;
449+ const rawColumns = await sequelize . query ( `SHOW FULL COLUMNS FROM ${ tableName } ` , {
450+ type : sequelize . QueryTypes . SELECT ,
451+ raw : true
452+ } ) ;
453+ const mappedTableName = getMappedTableName ( tableName ) ;
454+ Object . values ( rawColumns ) . forEach ( ( rawColumn ) => {
455+ const columnName = rawColumn . Field ;
456+ let type = MakeGraphql . typeMapping ( columns [ columnName ] . type , mappedTableName ) ;
457+ if ( type === 'Enum' ) {
458+ const enumObj = this . getEnums ( columns [ columnName ] . type , columnName , mappedTableName ) ;
459+ type = enumObj . name ;
460+ enums . push ( enumObj ) ;
461+ }
462+
463+ columns [ columnName ] . type = type ;
464+ columns [ columnName ] . unique = rawColumn . Key === 'UNI' ;
465+ columns [ columnName ] . comment = rawColumn . Comment ;
466+ columns [ columnName ] . autoIncrement = rawColumn . Extra . startsWith ( 'auto_increment' ) === true ;
467+ } ) ;
468+
469+ const indexes = await MakeEntity . getIndexes ( tableName , sequelize ) ;
470+ const schemaFile = `${ schemaPath } /${ tableName } .graphqls` ;
471+ try {
472+ fs . accessSync ( schemaFile ) ;
473+ logger . info ( 'Graphql schema file %s generate override, already exists by %s' , tableName , schemaFile ) ;
474+ } catch ( e ) {
475+ logger . info ( 'Graphql schema file %s generated as %s' , tableName , schemaFile ) ;
476+ }
477+ fs . writeFileSync ( schemaFile , _ . template ( schemaTemplate ) ( {
478+ tableName,
479+ mappedTableName,
480+ columns,
481+ indexes,
482+ enums
483+ } ) ) ;
484+ } ;
485+
486+ //Skip sequelize migrate table
487+ await Promise . all ( Object . values ( tables ) . filter ( t => ! [ 'sequelizemeta' , 'tramp_migrations' ] . includes ( t ) ) . map ( tableHandler ) ) ;
293488 logger . info ( 'All DB schemas generated' ) ;
294489 }
295490}
0 commit comments