Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CRM V2 Company contacts view #1013

Merged
merged 10 commits into from
May 14, 2024
39 changes: 39 additions & 0 deletions app/models/company-contact.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict'

/**
* Model for company contact (crm_v2.company_contacts)
* @module CompanyContactModel
*/

const { Model } = require('objection')

const BaseModel = require('./base.model.js')

class CompanyContactModel extends BaseModel {
static get tableName () {
return 'company_contacts'
}

static get relationMappings () {
return {
companies: {
relation: Model.HasManyRelation,
modelClass: 'company.model',
join: {
from: 'company_contacts.companyId',
to: 'companies.id'
}
},
contacts: {
relation: Model.HasManyRelation,
modelClass: 'contact.model',
join: {
from: 'company_contacts.contactId',
to: 'contacts.id'
}
}
}
}
}

module.exports = CompanyContactModel
43 changes: 43 additions & 0 deletions db/migrations/legacy/20240513145729_water-add-company-contacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict'

const tableName = 'company_contacts'

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function (knex) {
return knex
.schema
.withSchema('crm_v2')
.createTable(tableName, (table) => {
// Primary Key
table.uuid('company_contact_id').primary().defaultTo(knex.raw('gen_random_uuid()'))

// Data
table.boolean('is_default')
table.boolean('is_test')
table.boolean('water_abstraction_alerts_enabled')
table.date('end_date')
table.date('start_date')
table.string('email_address')
table.uuid('company_id')
table.uuid('contact_id')
table.uuid('role_id')

// Legacy timestamps
table.timestamp('date_created', { useTz: false }).notNullable().defaultTo(knex.fn.now())
table.timestamp('date_updated', { useTz: false }).notNullable().defaultTo(knex.fn.now())
})
}

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex
.schema
.withSchema('crm_v2')
.dropTableIfExists(tableName)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict'

const viewName = 'company_contacts'
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function (knex) {
return knex
.schema
.createView(viewName, (view) => {
// NOTE: We have commented out unused columns from the source table
view.as(knex('company_contacts').withSchema('crm_v2').select([
'company_contacts.company_contact_id AS id',
'company_contacts.company_id',
'company_contacts.contact_id',
'company_contacts.role_id',
'company_contacts.date_created AS created_at',
'company_contacts.date_updated AS updated_at'
// company_contacts.is_default
// company_contacts.email_address
// company_contacts.start_date
// company_contacts.end_date
// company_contacts.is_test
// company_contacts.water_abstraction_alerts_enabled
]))
})
}

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex
.schema
.dropViewIfExists(viewName)
}
103 changes: 103 additions & 0 deletions test/models/company-contacts.model.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
'use strict'

// Test framework dependencies
const Lab = require('@hapi/lab')
const Code = require('@hapi/code')

const { describe, it, beforeEach } = exports.lab = Lab.script()
const { expect } = Code

// Test helpers
const CompanyContactHelper = require('../support/helpers/company-contact.helper.js')
const CompanyHelper = require('../support/helpers/company.helper.js')
const CompanyModel = require('../../app/models/company.model.js')
const ContactsHelper = require('../support/helpers/contact.helper.js')
const ContactsModel = require('../../app/models/contact.model.js')
const DatabaseSupport = require('../support/database.js')

// Thing under test
const CompanyContactModel = require('../../app/models/company-contact.model.js')

describe('Company Contacts model', () => {
let testRecord

beforeEach(async () => {
await DatabaseSupport.clean()
})

describe('Basic query', () => {
beforeEach(async () => {
testRecord = await CompanyContactHelper.add()
})

it('can successfully run a basic query', async () => {
const result = await CompanyContactModel.query().findById(testRecord.id)

expect(result).to.be.an.instanceOf(CompanyContactModel)
expect(result.id).to.equal(testRecord.id)
})
})

describe('Relationships', () => {
describe('when linking to companies', () => {
let testCompany
beforeEach(async () => {
testRecord = await CompanyContactHelper.add()

testCompany = await CompanyHelper.add({
id: testRecord.companyId
})
})

it('can successfully run a related query', async () => {
const query = await CompanyContactModel.query()
.innerJoinRelated('companies')

expect(query).to.exist()
})

it('can eager load the companies', async () => {
const result = await CompanyContactModel.query()
.findById(testRecord.id)
.withGraphFetched('companies')

expect(result).to.be.instanceOf(CompanyContactModel)
expect(result.id).to.equal(testRecord.id)

expect(result.companies).to.be.an.array()
expect(result.companies[0]).to.be.an.instanceOf(CompanyModel)
expect(result.companies).to.include(testCompany)
})
})
describe('when linking to contacts', () => {
let testContact
beforeEach(async () => {
testRecord = await CompanyContactHelper.add()

testContact = await ContactsHelper.add({
id: testRecord.contactId
})
})

it('can successfully run a related query', async () => {
const query = await CompanyContactModel.query()
.innerJoinRelated('contacts')

expect(query).to.exist()
})

it('can eager load the company contacts', async () => {
const result = await CompanyContactModel.query()
.findById(testRecord.id)
.withGraphFetched('contacts')

expect(result).to.be.instanceOf(CompanyContactModel)
expect(result.id).to.equal(testRecord.id)

expect(result.contacts).to.be.an.array()
expect(result.contacts[0]).to.be.an.instanceOf(ContactsModel)
expect(result.contacts).to.include(testContact)
})
})
})
})
55 changes: 55 additions & 0 deletions test/support/helpers/company-contact.helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict'

/**
* @module CompanyContactHelper
*/

const CompanyContactModel = require('../../../app/models/company-contact.model.js')
const { generateUUID } = require('../../../app/lib/general.lib.js')

/**
* Add a new company contact
*
* If no `data` is provided, default values will be used. These are
*
* - `companyId` - [random UUID]
* - `contactId` - [random UUID]
* - `roleId` - [random UUID]
*
* @param {Object} [data] Any data you want to use instead of the defaults used here or in the database
*
* @returns {Promise<module:CompanyContactModel>} The instance of the newly created record
*/
function add (data = {}) {
const insertData = defaults(data)

return CompanyContactModel.query()
.insert({ ...insertData })
.returning('*')
}

/**
* Returns the defaults used
*
* It will override or append to them any data provided. Mainly used by the `add()` method, we make it available
* for use in tests to avoid having to duplicate values.
*
* @param {Object} [data] Any data you want to use instead of the defaults used here or in the database
*/
function defaults (data = {}) {
const defaults = {
companyId: generateUUID(),
contactId: generateUUID(),
roleId: generateUUID()
}

return {
...defaults,
...data
}
}

module.exports = {
add,
defaults
}
Loading