Ver código fonte

Initialize command

Alan Colon 7 anos atrás
pai
commit
c4fba515ef

+ 1 - 1
app/crud/pages/list.js

@@ -43,7 +43,7 @@ const list = (opts) => {
                       View
                     </md-button>
                     <md-button
-                      ng-if="!$ctrl.api.claims.${opts.constantName}_DELETE"
+                      ng-if="$ctrl.api.claims.${opts.constantName}_DELETE"
                       ng-click="$ctrl.delete(${raw(opts.camelName)})">
                       <md-icon md-svg-src="${deleteIcon}"></md-icon>
                       Delete

+ 26 - 4
bin/project.js

@@ -1,3 +1,4 @@
+const _ = require('lodash')
 const Vorpal = require('vorpal')
 const prompt = require('password-prompt')
 const database = require('../lib/database')
@@ -53,6 +54,21 @@ const main = async () => {
     }
   })
 
+  vorpal.command('initialize', 'Initializes database')
+  .action(async () => {
+    await database.sequelize.sync()
+    await Promise.all(
+      _.chain(database.setup.migrations)
+        .toPairs()
+        .map(async ([namespace, migs]) => {
+          const version = migs.map(x => x.version).reduce((a, b) => Math.max(a, b), 0)
+          console.log(`Setting ${namespace} to ${version}`)
+          await database.setup.setVersion(namespace, version)
+        })
+    )
+    await initDb()
+  })
+
   vorpal.delimiter('project>')
   if (process.argv.length > 2) {
     await vorpal.parse(process.argv)
@@ -61,9 +77,11 @@ const main = async () => {
   }
 }
 
-main().catch(err => {
-  console.error(chalk.red('Runtime Error!'))
-  console.error(err)
+setImmediate(() => {
+  main().catch(err => {
+    console.error(chalk.red('Runtime Error!'))
+    console.error(err)
+  })
 })
 
 process.on('uncaughtException', (err) => {
@@ -74,4 +92,8 @@ process.on('unhandledRejection', (err) => {
   console.error(chalk.red(`Unhandled Promise Failure!`))
   console.error(err)
   process.exit(1)
-})
+})
+
+module.exports = {
+  vorpal
+}

+ 2 - 1
lib/controllers/auth/permissions.js

@@ -30,5 +30,6 @@ const list = (req, res) => {
 
 module.exports = {
   register,
-  list
+  list,
+  permissions
 }

+ 67 - 3
lib/database/index.js

@@ -6,9 +6,55 @@ const User = require('./user')
 const Session = require('./session')
 const Role = require('./role')
 const setup = require('./setup')
+const { dict } = require('../util')
+const { Op } = require('sequelize')
 
 const UserRole = User.belongsToMany(Role, { through: 'userRoles' })
 
+const isUUID = (str) =>
+  typeof str === 'string' &&
+  /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str)
+
+const fetch = async (Type, refs) => {
+  if (!Array.isArray(refs)) {
+    return (await fetch(Type, [refs]))[0]
+  }
+  let ret = refs.slice(0)
+  const keys = []
+  const ids = []
+  for (let ref of refs) {
+    if (isUUID(ref)) ids.push(ref)
+    else if (typeof ref === 'string') keys.push(ref)
+  }
+  if (keys.length || ids.length) {
+    const or = []
+    if (ids.length) or.push({
+      id: {
+        [Op.in]: ids
+      }
+    })
+    if (keys.length) or.push({
+      key: {
+        [Op.in]: keys
+      }
+    })
+    const recs = dict(await Type.findAll({
+      where: {
+        [Op.or]: or
+      }
+    }))
+    if (recs.length !== ids.length + keys.length) {
+      const missing = [
+        ...ids.filter(id => !recs[id]),
+        ...keys.filter(key => !recs[key])
+      ].join(', ')
+      throw new Error(`Not all references retrieved. Expected ${ids.length + keys.length}, got ${recs.length}. Missing ${missing} from ${Type.name}.`)
+    }
+    ret = ret.map(ref => recs[ref] || ref)
+  }
+  return dict(ret)
+}
+
 const upsert = async (Type, object, fields) => {
   if (!fields) {
     fields = ['key']
@@ -19,15 +65,31 @@ const upsert = async (Type, object, fields) => {
     }
   }
   const existing = await Type.findOne({where: _.pick(object, fields)})
+  let record
   if (existing) {
     Object.assign(existing, object)
     await existing.save()
-    return existing
+    record = existing
   } else {
-    return await Type.create(object)
+    record = await Type.create(object)
+  }
+
+  for (let assoc of Object.values(Type.associations)) {
+    if (object[assoc.as]) {
+      if (assoc.associationType === 'BelongsToMany' || assoc.associationType === 'BelongsTo') {
+        const recs = await fetch(assoc.target, object[assoc.as])
+        await assoc.set(record, recs)
+      }
+    }
   }
+
+  return record
 }
 
+const fill = (Type, objects, fields) => Promise.all(objects.map(object =>
+  upsert(Type, object, fields)
+))
+
 module.exports = {
   init: () => {
     //return sequelize.sync()
@@ -38,5 +100,7 @@ module.exports = {
   Role,
   UserRole,
   upsert,
-  setup
+  setup,
+  fill,
+  fetch
 }

+ 3 - 1
lib/database/setup.js

@@ -80,5 +80,7 @@ const migrateAll = async () => {
 module.exports = {
   getVersion,
   migrate,
-  migrateAll
+  migrateAll,
+  migrations,
+  setVersion
 }

+ 12 - 2
lib/util.js

@@ -23,15 +23,25 @@ const diffBy = (before, after, selector) => {
 
 const sanitize = _.curry(async (req, data) => {
   if (data) {
-    if (Array.isArray(data)) return Promise.all(data.map(sanitize(req)))
+    if (Array.isArray(data)) return await Promise.all(data.map(sanitize(req)))
     if (data.sanitize) return await data.sanitize(req)
     if (data.toJSON) return data.toJSON()
   }
   return data
 })
 
+const dict = (collection) => {
+  collection.forEach(item => {
+    collection[item.key] = item
+    collection[item.id] = item
+  })
+  return collection
+}
+
+
 module.exports = {
   fillPath,
   diffBy,
-  sanitize
+  sanitize,
+  dict
 }