| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | const types = require('../types'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const createColumn = (name, attribute) => { | 
					
						
							|  |  |  |   const { type, args = [], ...opts } = getColumnType(attribute); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     name, | 
					
						
							|  |  |  |     type, | 
					
						
							|  |  |  |     args, | 
					
						
							|  |  |  |     ...opts, | 
					
						
							|  |  |  |     ...(attribute.column || {}), | 
					
						
							|  |  |  |     // TODO: allow passing custom params to the DB from the model definition
 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const shouldCreateColumn = attribute => { | 
					
						
							|  |  |  |   return types.isScalar(attribute.type); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const createTable = meta => { | 
					
						
							|  |  |  |   const table = { | 
					
						
							|  |  |  |     // TODO: allow passing custom params to the DB from the model definition
 | 
					
						
							|  |  |  |     name: meta.tableName, | 
					
						
							|  |  |  |     indexes: meta.indexes || [], | 
					
						
							|  |  |  |     foreignKeys: meta.foreignKeys || [], | 
					
						
							|  |  |  |     columns: [], | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // TODO: handle indexes
 | 
					
						
							|  |  |  |   // TODO: handle foreignKeys
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (const key in meta.attributes) { | 
					
						
							|  |  |  |     const attribute = meta.attributes[key]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO: if relation & has a joinColumn -> create it
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (types.isRelation(attribute.type)) { | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |       if (attribute.joinColumn && attribute.owner) { | 
					
						
							|  |  |  |         // TODO: pass uniquness for oneToOne to avoid create more than one to one
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |         const { name: columnName, referencedColumn, referencedTable } = attribute.joinColumn; | 
					
						
							|  |  |  |         table.columns.push( | 
					
						
							|  |  |  |           createColumn(columnName, { | 
					
						
							|  |  |  |             type: 'integer', | 
					
						
							|  |  |  |             unsigned: true, | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         table.foreignKeys.push({ | 
					
						
							|  |  |  |           // TODO: generate a name
 | 
					
						
							|  |  |  |           name: `${columnName}_fk`, | 
					
						
							|  |  |  |           columns: [columnName], | 
					
						
							|  |  |  |           referencedTable, | 
					
						
							|  |  |  |           referencedColumns: [referencedColumn], | 
					
						
							|  |  |  |           onDelete: 'SET NULL', // NOTE: could allow ocnifguration
 | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if (shouldCreateColumn(attribute)) { | 
					
						
							|  |  |  |       // TODO: if column is unique then add a unique index outside so we can easily do the diff
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const column = createColumn(key, meta.attributes[key]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (column.unique) { | 
					
						
							|  |  |  |         table.indexes.push({ | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  |           type: 'unique', | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |           name: `${table.name}_${column.name}_unique`, | 
					
						
							|  |  |  |           columns: [column.name], | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (column.primary) { | 
					
						
							|  |  |  |         table.indexes.push({ | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  |           type: 'primary', | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |           name: `${table.name}_${column.name}_primary`, | 
					
						
							|  |  |  |           columns: [column.name], | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       table.columns.push(column); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return table; | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const getColumnType = attribute => { | 
					
						
							|  |  |  |   if (attribute.columnType) { | 
					
						
							|  |  |  |     return attribute.columnType; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (attribute.type) { | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     case 'increments': { | 
					
						
							|  |  |  |       return { type: 'increments', args: [{ primary: true }] }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // We might want to convert email/password to string types before going into the orm with specific validators & transformers
 | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  |     case 'password': | 
					
						
							|  |  |  |     case 'email': | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     case 'string': { | 
					
						
							|  |  |  |       return { type: 'string' }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case 'uid': { | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         type: 'string', | 
					
						
							|  |  |  |         unique: true, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case 'richtext': | 
					
						
							|  |  |  |     case 'text': { | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         type: 'text', | 
					
						
							|  |  |  |         args: ['longtext'], | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case 'json': { | 
					
						
							| 
									
										
										
										
											2021-06-29 16:27:35 +02:00
										 |  |  |       return { type: 'jsonb' }; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     case 'enumeration': { | 
					
						
							| 
									
										
										
										
											2021-06-17 19:51:35 +02:00
										 |  |  |       return { | 
					
						
							|  |  |  |         type: 'enum', | 
					
						
							|  |  |  |         args: [ | 
					
						
							|  |  |  |           attribute.enum /*,{ useNative: true, existingType: true, enumName: 'foo_type', schemaName: 'public' }*/, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 'integer': { | 
					
						
							|  |  |  |       return { type: 'integer' }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case 'biginteger': { | 
					
						
							|  |  |  |       return { type: 'bigInteger' }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // TODO: verify usage of double vs float
 | 
					
						
							|  |  |  |     case 'float': { | 
					
						
							|  |  |  |       return { type: 'double', args: [] }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // TODO: define precision
 | 
					
						
							|  |  |  |     case 'decimal': { | 
					
						
							|  |  |  |       return { type: 'decimal', args: [10, 2] }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case 'date': { | 
					
						
							|  |  |  |       return { type: 'date' }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // TODO: define precision
 | 
					
						
							|  |  |  |     case 'time': { | 
					
						
							|  |  |  |       return { type: 'time', args: [{ precision: 3 }] }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case 'datetime': { | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         type: 'datetime', | 
					
						
							|  |  |  |         args: [ | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             useTz: false, | 
					
						
							|  |  |  |             precision: 6, // TODO: to define
 | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // TODO: handle defaults
 | 
					
						
							|  |  |  |     case 'timestamp': { | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         type: 'timestamp', | 
					
						
							|  |  |  |         args: [ | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             useTz: false, | 
					
						
							|  |  |  |             precision: 6, // TODO: to define
 | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case 'boolean': { | 
					
						
							|  |  |  |       return { type: 'boolean' }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     default: { | 
					
						
							|  |  |  |       throw new Error(`Unknow type ${attribute.type}`); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const metadataToSchema = metadata => { | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |   const schema = { | 
					
						
							|  |  |  |     tables: [], | 
					
						
							|  |  |  |     addTable(table) { | 
					
						
							|  |  |  |       this.tables.push(table); | 
					
						
							|  |  |  |       return this; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |   metadata.forEach(metadata => { | 
					
						
							|  |  |  |     schema.addTable(createTable(metadata)); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |   return schema; | 
					
						
							| 
									
										
										
										
											2021-06-02 15:53:22 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | module.exports = { metadataToSchema, createTable }; |