Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions src/generators/src/infra/database/migrations/migrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const { snakeCase, camelCase } = require('lodash')
const fs = require("fs")
const glob = require('glob')
const path = require('path')
const { requireHerbarium } = require('../../../../utils')
const { requireHerbarium, requireHerbs } = require('../../../../utils')

module.exports =
async ({ template: { generate }, filesystem }, command) =>
Expand All @@ -12,6 +12,7 @@ module.exports =
process.stdout.write(`Generating Migration\n`)

const herbarium = requireHerbarium(command, filesystem.cwd())
const herbs = requireHerbs(filesystem.cwd())
const entities = herbarium.entities.all

const cwd = filesystem.cwd().replace(new RegExp('\\\\', 'g'), '/')
Expand All @@ -26,15 +27,11 @@ module.exports =
}

function type2Str(Type) {
const nativeTypes = [Boolean, Number, String, Array, Object, Date, Function]

if (nativeTypes.includes(Type)) {
const _type = new Type()
if (_type instanceof String) return 'string'
if (_type instanceof Number) return 'integer'
if (_type instanceof Boolean) return 'boolean'
if (_type instanceof Date) return 'timestamp'
}
const _type = new Type()
if (_type instanceof String) return 'string'
if (_type instanceof Number) return 'integer'
if (_type instanceof Boolean) return 'boolean'
if (_type instanceof Date) return 'timestamp'
}

function getDBType(appDir) {
Expand All @@ -47,11 +44,35 @@ module.exports =
const columns = []
Object.keys(schema).forEach((prop) => {
const { name, type, options } = schema[prop]
columns.push(`table.${type2Str(type)}('${snakeCase(name)}')${options.isId ? '.primary()' : ''}`)

const nativeTypes = [Boolean, Number, String, Date]
if (!nativeTypes.includes(type)) return

const typeString = type2Str(type)
columns.push(`table.${typeString}('${snakeCase(name)}')${options.isId ? '.primary()' : ''}`)
})
return columns
}

function isArrayWithType(value) {
return Array.isArray(value) && value.length === 1
}

function identifyRef(schema) {
const refs = []
Object.values(schema).forEach(({ type, name }) => {
if (herbs.entity.isEntity(type)) {
const typeSchema = type.prototype.meta.schema
const idRef = Object.values(typeSchema).find(column => column.options.isId)?.name
refs.push({ id: idRef, columnName: `${camelCase(name)}Id`, table: `${camelCase(type.name)}s`, relationship: 'One-to-One' })

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both table and columns name should be snake_cases for DB to keep with the current standard.

ex: userId -> user_id

}

if (isArrayWithType(type) && herbs.entity.isEntity(type[0]))
refs.push({ table: `${camelCase(type[0].name)}s`, relationship: 'One-to-Many' })

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both table and columns name should be snake_cases for DB to keep with the current standard.

ex: userId -> user_id

})
return refs
}

const db = getDBType(filesystem.cwd())
const migrationName = new Date()
.toISOString()
Expand All @@ -60,11 +81,14 @@ module.exports =
const migrationFullPath = path.normalize(`${migrationsPath}/${migrationName}_${camelCase(name)}s.js`)

const columns = createColumns(schema)
const ref = identifyRef(schema)
const idColumn = Object.values(schema).find(column => column.options.isId)?.name


await generate({
template: `infra/data/database/${db.toLowerCase()}/migration.ejs`,
target: migrationFullPath,
props: { table: `${camelCase(name)}s`, columns: columns }
props: { table: `${camelCase(name)}s`, externalColumnName: `${camelCase(name)}Id`, columns, ref, idColumn }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both table and columns name should be snake_cases for DB to keep with the current standard.

ex: userId -> user_id

})
process.stdout.write(` New: ${migrationFullPath}\n`)

Expand Down
7 changes: 6 additions & 1 deletion src/generators/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ module.exports = {
const herbariumPath = `${appPath}/src/domain/herbarium.js`
let herbarium
if (command === "update" || command === "spec") {
herbarium = require(herbariumPath)
herbarium = require(herbariumPath).herbarium
}
else
herbarium = require('@herbsjs/herbarium').herbarium
herbarium.requireAll()
return herbarium
},
requireHerbs: (appPath) => {
const herbariumPath = `${appPath}/src/domain/herbarium.js`
const herbs = require(herbariumPath).herbs
return herbs
},
usingMongo: (base) => fs.existsSync(path.normalize(`${base}/src/infra/config/mongo.js`))
}
3 changes: 2 additions & 1 deletion src/templates/domain/herbarium.ejs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
const { herbarium } = require('@herbsjs/herbarium')
module.exports = herbarium
const herbs = require('@herbsjs/herbs')
module.exports = { herbarium, herbs }
51 changes: 39 additions & 12 deletions src/templates/infra/data/database/postgres/migration.ejs
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@

exports.up = async function (knex) {
knex.schema.hasTable('<%- props.table %>')
.then(function (exists) {
if (exists) return
return knex.schema
.createTable('<%- props.table %>', function (table) {<% for(colum of props.columns) { %>
<%- colum %><% } %>
table.timestamps()
})
})
return Promise.all([
knex.schema.hasTable('<%- props.table %>')
.then(function (exists) {
if (exists) return
return knex.schema
.createTable('<%- props.table %>', function (table) {
<% for(colum of props.columns) {%>
<%- colum %> <%}%>
<%if (props.ref) {
props.ref.forEach(function(link){
if (link.relationship === 'One-to-One') { %>
// table.integer('<%-link.columnName %>').unsigned().nullable()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment is necessary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the idea are to not create a migration that does not work, due to not has an order of migrations when we write the files. These relationships throw errors due the dependence dont exist yet ...

// table.foreign('<%-link.columnName %>').references('<%- link.id %>').inTable('<%- link.table %>')
<% }
})
} %>
table.timestamps()
})
}),
<%if (props.ref) {
props.ref.forEach(function(link){
if (link.relationship === 'One-to-Many') { %>
// knex.schema.table('<%- link.table %>', function (table) {
// table.integer('<%-props.externalColumnName %>').unsigned().index().references('<%- props.idColumn %>').inTable('<%- props.table %>')
// })
<% }
})
} %>
])
}

exports.down = function (knex) {
return knex.schema
.dropTableIfExists('<%- props.table %>')
return Promise.all([
knex.schema
.dropTableIfExists('<%- props.table %>'),
<%if (props.ref) {
props.ref.forEach(function(link){
if (link.relationship === 'One-to-Many') { %>
// knex.schema.table('<%- link.table %>', function (table) {
// table.dropColumn('<%-props.externalColumnName %>')})
<% }})} %>
])
}