Verified Commit 0da22ea1 authored by aguestuser's avatar aguestuser

[347] add `hasOne` association btw/ channel & recycleRequest

parent 6090a036
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.renameColumn('recycleRequests', 'phoneNumber', 'channelPhoneNumber')
return queryInterface.changeColumn('recycleRequests', 'channelPhoneNumber', {
type: Sequelize.STRING,
primaryKey: true,
allowNull: false,
unique: true,
// old --^
// new --v
references: {
model: {
tableName: 'channels',
},
key: 'phoneNumber',
}
})
},
down: async (queryInterface, Sequelize) => {
await queryInterface.changeColumn('recycleRequests', 'channelPhoneNumber', {
type: Sequelize.STRING,
primaryKey: true,
allowNull: false,
unique: true,
})
return queryInterface.renameColumn('recycleRequests', 'channelPhoneNumber', 'phoneNumber')
}
};
......@@ -44,31 +44,18 @@ const channelOf = (sequelize, DataTypes) => {
},
})
channel.associate = db => {
channel.hasMany(db.membership, {
hooks: true,
onDelete: 'cascade',
})
channel.hasMany(db.deauthorization, {
hooks: true,
onDelete: 'cascade',
})
channel.hasMany(db.invite, {
hooks: true,
onDelete: 'cascade',
})
channel.hasOne(db.messageCount, {
hooks: true,
onDelete: 'cascade',
})
const associationDefaults = {
hooks: true,
onDelete: 'cascade',
}
channel.hasMany(db.hotlineMessage, {
hooks: true,
onDelete: 'cascade',
})
channel.associate = db => {
channel.hasMany(db.deauthorization, associationDefaults)
channel.hasMany(db.hotlineMessage, associationDefaults)
channel.hasMany(db.invite, associationDefaults)
channel.hasMany(db.membership, associationDefaults)
channel.hasOne(db.messageCount, associationDefaults)
channel.hasOne(db.recycleRequest, associationDefaults)
}
return channel
......
const { isPhoneNumber } = require('../validations')
const recycleRequestOf = (sequelize, Sequelize) =>
sequelize.define('recycleRequest', {
phoneNumber: {
const recycleRequestOf = (sequelize, Sequelize) => {
const recycleRequest = sequelize.define('recycleRequest', {
channelPhoneNumber: {
type: Sequelize.STRING,
primaryKey: true,
allowNull: false,
unique: true,
validate: isPhoneNumber,
references: {
model: {
tableName: 'channels',
},
key: 'phoneNumber',
},
},
createdAt: {
type: Sequelize.DATE,
......@@ -21,4 +27,11 @@ const recycleRequestOf = (sequelize, Sequelize) =>
},
})
recycleRequest.associate = db => {
recycleRequest.belongsTo(db.channel)
}
return recycleRequest
}
module.exports = { recycleRequestOf }
......@@ -69,6 +69,17 @@ describe('channel model', () => {
},
)
const createChannelWithRecycleRequest = () =>
db.channel.create(
{
...channelFactory(),
recycleRequest: {},
},
{
include: [{ model: db.recycleRequest }],
},
)
before(async () => {
db = await run()
})
......@@ -78,6 +89,7 @@ describe('channel model', () => {
db.messageCount.destroy({ where: {}, force: true }),
db.membership.destroy({ where: {}, force: true }),
db.hotlineMessage.destroy({ where: {}, force: true }),
db.recycleRequest.destroy({ where: {}, force: true }),
])
await db.channel.destroy({ where: {}, force: true })
})
......@@ -248,5 +260,28 @@ describe('channel model', () => {
expect(await db.hotlineMessage.count()).to.eql(hotlineMessageCount - 2)
})
})
describe('recycle request', () => {
let recycleRequest
beforeEach(async () => {
channel = await createChannelWithRecycleRequest()
recycleRequest = await channel.getRecycleRequest()
})
it('has one recycle request', () => {
expect(recycleRequest).to.be.an('object')
})
it('deletes the recycle reqeust when it deletes channel', async () => {
const recycleRequestCount = await db.recycleRequest.count()
await channel.destroy()
expect(await db.recycleRequest.count()).to.eql(recycleRequestCount - 1)
})
it('returns null if no recycle requests exist for the account', async () => {
channel = await db.channel.create(channelFactory())
expect(await channel.getRecycleRequest()).to.be.null
})
})
})
})
import { expect } from 'chai'
import { describe, it, before, after, afterEach } from 'mocha'
import { describe, it, before, beforeEach, after, afterEach } from 'mocha'
import { run } from '../../../../app/db/index'
import { genPhoneNumber } from '../../../support/factories/phoneNumber'
import { channelFactory } from '../../../support/factories/channel'
describe('recycleRequest model', () => {
let db
let phoneNumber = genPhoneNumber()
let db, channel
let channelPhoneNumber = genPhoneNumber()
before(async () => (db = await run()))
afterEach(async () => await db.recycleRequest.destroy({ where: {} }))
beforeEach(async () => {
channel = await db.channel.create(channelFactory({ phoneNumber: channelPhoneNumber }))
})
afterEach(async () => {
await db.recycleRequest.destroy({ where: {} })
await db.channel.destroy({ where: {} })
})
after(async () => await db.stop())
it('has the correct fields', async () => {
const recycleRequest = await db.recycleRequest.create({ phoneNumber })
expect(recycleRequest.phoneNumber).to.be.a('string')
const recycleRequest = await db.recycleRequest.create({ channelPhoneNumber })
expect(recycleRequest.channelPhoneNumber).to.be.a('string')
expect(recycleRequest.createdAt).to.be.a('Date')
expect(recycleRequest.updatedAt).to.be.a('Date')
})
describe('validations', () => {
it('requires a phoneNumber', async () => {
const err = await db.recycleRequest.create({ phoneNumber: undefined }).catch(e => e)
expect(err.message).to.include('phoneNumber cannot be null')
it('requires a channelPhoneNumber', async () => {
const err = await db.recycleRequest.create({ channelPhoneNumber: undefined }).catch(e => e)
expect(err.message).to.include('channelPhoneNumber cannot be null')
})
it('requires phone number to have valid e164 format', async () => {
const err = await db.recycleRequest.create({ phoneNumber: 'foobar' }).catch(e => e)
const err = await db.recycleRequest.create({ channelPhoneNumber: 'foobar' }).catch(e => e)
expect(err.message).to.include('Validation error')
})
it("doesn't allow the same phone number to be enqueued twice", async () => {
await db.recycleRequest.create({ phoneNumber })
const err = await db.recycleRequest.create({ phoneNumber }).catch(e => e)
await db.recycleRequest.create({ channelPhoneNumber })
const err = await db.recycleRequest.create({ channelPhoneNumber }).catch(e => e)
expect(err.name).to.equal('SequelizeUniqueConstraintError')
})
it("doesn't allow a recycle request for a channel that does not exist", async () => {
const err = await db.recycleRequest
.create({ channelPhoneNumber: genPhoneNumber() })
.catch(e => e)
expect(err.name).to.equal('SequelizeForeignKeyConstraintError')
})
})
describe('associations', () => {
it('belongs to a channel', async () => {
const recycleRequest = await db.recycleRequest.create({
channelPhoneNumber: channel.phoneNumber,
})
expect((await recycleRequest.getChannel()).dataValues).to.eql(channel.dataValues)
})
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment