Skip to content
This repository has been archived by the owner on Jul 17, 2022. It is now read-only.

Commit

Permalink
feat(shipment): implement hubs persistence and update
Browse files Browse the repository at this point in the history
  • Loading branch information
coderbyheart committed Aug 5, 2021
1 parent 7b171cc commit 02b7380
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 24 deletions.
134 changes: 115 additions & 19 deletions src/resolvers/shipment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { isEqual, xor } from 'lodash'
import Group from '../models/group'
import Shipment, { ShipmentAttributes } from '../models/shipment'
import ShipmentExport from '../models/shipment_export'
import ShipmentReceivingHub from '../models/shipment_receiving_hub'
import ShipmentSendingHub from '../models/shipment_sending_hub'
import {
MutationResolvers,
QueryResolvers,
Expand All @@ -29,6 +31,17 @@ const SHIPMENT_STATUSES_ALLOWED_FOR_NON_ADMINS: Readonly<ShipmentStatus[]> = [
ShipmentStatus.Staging,
] as const

const include = [
{
model: Group,
as: 'sendingHubs',
},
{
model: Group,
as: 'receivingHubs',
},
]

// Shipment query resolvers

// - list shipments by status
Expand Down Expand Up @@ -72,6 +85,7 @@ const listShipments: QueryResolvers['listShipments'] = async (
where: {
status,
},
include,
})
}

Expand All @@ -80,9 +94,12 @@ const listShipments: QueryResolvers['listShipments'] = async (
where: {
status: SHIPMENT_STATUSES_ALLOWED_FOR_NON_ADMINS,
},
include,
})

return Shipment.findAll()
return Shipment.findAll({
include,
})
}

// - get shipment
Expand All @@ -94,11 +111,9 @@ const shipment: QueryResolvers['shipment'] = async (_, { id }, context) => {
}

const shipment = await Shipment.findByPk(valid.value.id, {
include: ['sendingHubs', 'receivingHubs'],
include,
})

console.log(shipment?.sendingHubs)

if (!shipment) {
throw new ApolloError(`No shipment exists with ID "${valid.value.id}"`)
}
Expand Down Expand Up @@ -209,8 +224,27 @@ const addShipment: MutationResolvers['addShipment'] = async (
statusChangeTime: new Date(),
pricing: valid.value.pricing,
})
// FIXME: how to persist M:N relations?
return shipment
await Promise.all([
Promise.all(
sendingHubs.map((hub) =>
ShipmentSendingHub.create({
hubId: hub.id,
shipmentId: shipment.id,
}),
),
),
Promise.all(
receivingHubs.map((hub) =>
ShipmentReceivingHub.create({
hubId: hub.id,
shipmentId: shipment.id,
}),
),
),
])
return Shipment.findByPk(shipment.id, {
include,
}) as Promise<Shipment>
}

// - update shipment
Expand Down Expand Up @@ -250,16 +284,16 @@ const updateShipment: MutationResolvers['updateShipment'] = async (
throw new ForbiddenError('updateShipment forbidden to non-admin users')
}

const shipment = await Shipment.findByPk(valid.value.id)
const shipment = await Shipment.findByPk(valid.value.id, { include })

if (shipment === null) {
throw new ApolloError(`No shipment exists with ID "${valid.value.id}"`)
}

const {
status,
receivingHubs,
sendingHubs,
receivingHubs: receivingHubsUpdate,
sendingHubs: sendingHubsUpdate,
labelMonth,
labelYear,
shippingRoute,
Expand All @@ -273,32 +307,31 @@ const updateShipment: MutationResolvers['updateShipment'] = async (
updateAttributes.statusChangeTime = new Date()
}

if (receivingHubs !== undefined) {
if (receivingHubsUpdate !== undefined) {
const loadedReceivingHubs = await Group.findAll({
where: { id: receivingHubs },
where: { id: receivingHubsUpdate },
})

if (loadedReceivingHubs.length !== receivingHubs.length) {
if (loadedReceivingHubs.length !== receivingHubsUpdate.length) {
const foundHubs = loadedReceivingHubs.map(({ id }) => id)
throw new ApolloError(
`Could not find receiving hubs: ${receivingHubs.filter(
`Could not find receiving hubs: ${receivingHubsUpdate.filter(
(id) => !foundHubs.includes(id),
)}`,
)
}

updateAttributes.receivingHubs = loadedReceivingHubs
}

if (sendingHubs) {
if (sendingHubsUpdate) {
const loadedSendingHubs = await Group.findAll({
where: { id: sendingHubs },
where: { id: sendingHubsUpdate },
})

if (loadedSendingHubs.length !== sendingHubs.length) {
if (loadedSendingHubs.length !== sendingHubsUpdate.length) {
const foundHubs = loadedSendingHubs.map(({ id }) => id)
throw new ApolloError(
`Could not find sending hubs: ${sendingHubs.filter(
`Could not find sending hubs: ${sendingHubsUpdate.filter(
(id) => !foundHubs.includes(id),
)}`,
)
Expand Down Expand Up @@ -349,7 +382,70 @@ const updateShipment: MutationResolvers['updateShipment'] = async (
updateAttributes.pricing = pricing
}

return shipment.update(updateAttributes)
await shipment.update(updateAttributes)

// Did sending hubs change?
if (updateAttributes.sendingHubs !== undefined) {
// Find IDs of sending hubs to delete
const oldSendingHubIds = shipment.sendingHubs.map(({ id }) => id)
const sendingHubsToDelete = oldSendingHubIds.filter(
(id) => !sendingHubsUpdate?.includes(id) ?? false,
)
// Find IDs of sending hubs to add
const sendingHubsToAdd =
sendingHubsUpdate?.filter((id) => !oldSendingHubIds.includes(id)) ?? []
// Execute
await Promise.all([
ShipmentSendingHub.destroy({
where: {
shipmentId: shipment.id,
hubId: sendingHubsToDelete,
},
}),
Promise.all(
sendingHubsToAdd.map((hubId) =>
ShipmentSendingHub.create({
shipmentId: shipment.id,
hubId,
}),
),
),
])
}

// Did receiving hubs change?
if (updateAttributes.receivingHubs !== undefined) {
// Find IDs of receiving hubs to delete
const oldReceivingHubIds = shipment.receivingHubs.map(({ id }) => id)
const receivingHubsToDelete = oldReceivingHubIds.filter(
(id) => !receivingHubsUpdate?.includes(id) ?? false,
)
// Find IDs of receiving hubs to add
const receivingHubsToAdd =
receivingHubsUpdate?.filter((id) => !oldReceivingHubIds.includes(id)) ??
[]
// Execute
await Promise.all([
ShipmentReceivingHub.destroy({
where: {
shipmentId: shipment.id,
hubId: receivingHubsToDelete,
},
}),
Promise.all(
receivingHubsToAdd.map((hubId) =>
ShipmentReceivingHub.create({
shipmentId: shipment.id,
hubId,
}),
),
),
])
}

return Shipment.findByPk(shipment.id, {
include,
}) as Promise<Shipment>
}

// Shipment custom resolvers
Expand Down
34 changes: 33 additions & 1 deletion src/tests/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { GraphQLResponse } from 'apollo-server-types'
import { Maybe } from 'graphql/jsutils/Maybe'
import Group from '../../models/group'
import Shipment from '../../models/shipment'
import ShipmentReceivingHub from '../../models/shipment_receiving_hub'
import ShipmentSendingHub from '../../models/shipment_sending_hub'
import UserAccount from '../../models/user_account'
import {
GroupCreateInput,
Expand Down Expand Up @@ -29,12 +31,42 @@ async function createShipment(input: ShipmentCreateInput): Promise<Shipment> {
Group.findAll({ where: { id: input.receivingHubs } }),
Group.findAll({ where: { id: input.sendingHubs } }),
])
return await Shipment.create({
const shipment = await Shipment.create({
...input,
pricing: input.pricing || undefined,
receivingHubs,
sendingHubs,
})
await Promise.all([
Promise.all(
sendingHubs.map((hub) =>
ShipmentSendingHub.create({
hubId: hub.id,
shipmentId: shipment.id,
}),
),
),
Promise.all(
receivingHubs.map((hub) =>
ShipmentReceivingHub.create({
hubId: hub.id,
shipmentId: shipment.id,
}),
),
),
])
return Shipment.findByPk(shipment.id, {
include: [
{
model: Group,
as: 'sendingHubs',
},
{
model: Group,
as: 'receivingHubs',
},
],
}) as Promise<Shipment>
}

export { createGroup, createShipment }
Expand Down
8 changes: 4 additions & 4 deletions src/tests/shipments_api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,18 @@ describe('Shipments API', () => {
},
})) as TypedGraphQLResponse<{ addShipment: Shipment }>

console.log(JSON.stringify(res.errors, null, 2))

expect(res.errors).toBeUndefined()
expect(res?.data?.addShipment?.shippingRoute).toEqual(
ShippingRoute.UkToFr,
)
expect(res?.data?.addShipment?.labelYear).toEqual(nextYear)
expect(res?.data?.addShipment?.labelMonth).toEqual(1)
expect(res?.data?.addShipment?.sendingHubs).toMatchObject({
expect(res?.data?.addShipment?.sendingHubs).toHaveLength(1)
expect(res?.data?.addShipment?.sendingHubs[0]).toMatchObject({
id: group1.id,
})
expect(res?.data?.addShipment?.receivingHubs).toMatchObject({
expect(res?.data?.addShipment?.receivingHubs).toHaveLength(1)
expect(res?.data?.addShipment?.receivingHubs[0]).toMatchObject({
id: group2.id,
})
})
Expand Down

0 comments on commit 02b7380

Please sign in to comment.