const _ = require('lodash') const config = require('../../config') const bcrypt = require('bcryptjs') const sequelize = require('./sequelize') 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 }, paranoid: false })) 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'] } for (var field of fields) { if (!object[field]) { throw new Error(`Missing upsert field '${field}' in ${JSON.stringify(object)}.`) } } const existing = await Type.findOne({where: _.pick(object, fields), paranoid: false}) let record if (existing) { Object.assign(existing, object) await existing.save() record = existing } else { 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() }, sequelize, User, Session, Role, UserRole, upsert, setup, fill, fetch }