Skip to content

Commit

Permalink
bugfix: claims are merged
Browse files Browse the repository at this point in the history
  • Loading branch information
jlarsson committed Sep 22, 2023
1 parent 4e0e863 commit 2993fa6
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 27 deletions.
13 changes: 9 additions & 4 deletions src/adverts/advert-mutations/claims/cancel-advert-claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import type { Services } from '../../../types'
import { getAdvertMeta } from '../../advert-meta'
import { AdvertClaimType } from '../../types'
import type { AdvertClaim, Advert, AdvertMutations } from '../../types'
import { mapTxResultToAdvertMutationResult } from '../mappers'
import {
mapTxResultToAdvertMutationResult,
normalizeAdvertClaims,
} from '../mappers'
import {
verifyAll,
verifyReservationLimits,
Expand Down Expand Up @@ -48,9 +51,11 @@ export const createCancelAdvertClaim =
)
return {
...advert,
claims: advert.claims
.filter(c => !matchClaim(c))
.filter(({ quantity }) => quantity > 0),
claims: normalizeAdvertClaims(
advert.claims
.filter(c => !matchClaim(c))
.filter(({ quantity }) => quantity > 0)
),
}
})
.verify((_, ctx) =>
Expand Down
26 changes: 15 additions & 11 deletions src/adverts/advert-mutations/claims/convert-advert-claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import type { Services } from '../../../types'
import { getAdvertMeta } from '../../advert-meta'
import { AdvertClaimType } from '../../types'
import type { AdvertClaim, Advert, AdvertMutations } from '../../types'
import { mapTxResultToAdvertMutationResult } from '../mappers'
import {
mapTxResultToAdvertMutationResult,
normalizeAdvertClaims,
} from '../mappers'
import {
verifyAll,
verifyReservationLimits,
Expand Down Expand Up @@ -49,16 +52,17 @@ export const createConvertAdvertClaim =
)
return {
...advert,
claims: advert.claims
.filter(c => !matchClaim(c))
.concat(
claims.map(c => ({
...c,
at: new Date().toISOString(),
type: newType,
}))
)
.filter(({ quantity }) => quantity > 0),
claims: normalizeAdvertClaims(
advert.claims
.filter(c => !matchClaim(c))
.concat(
claims.map(c => ({
...c,
at: new Date().toISOString(),
type: newType,
}))
)
),
}
})
.verify((_, ctx) =>
Expand Down
9 changes: 6 additions & 3 deletions src/adverts/advert-mutations/collecting/collect-advert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { TxErrors, txBuilder } from '../../../transactions'
import type { Services } from '../../../types'
import { getAdvertMeta } from '../../advert-meta'
import { AdvertClaimType, type Advert, type AdvertMutations } from '../../types'
import { mapTxResultToAdvertMutationResult } from '../mappers'
import {
mapTxResultToAdvertMutationResult,
normalizeAdvertClaims,
} from '../mappers'
import {
verifyAll,
verifyReservationLimits,
Expand Down Expand Up @@ -47,7 +50,7 @@ export const createCollectAdvert =
.reduce((s, v) => s + v, 0)
return {
...advert,
claims: [
claims: normalizeAdvertClaims([
...advert.claims.filter(({ by }) => by !== user.id), // all except mine
{
by: user.id,
Expand All @@ -61,7 +64,7 @@ export const createCollectAdvert =
quantity: collectedByMeCount + quantity,
type: AdvertClaimType.collected,
},
].filter(({ quantity }) => quantity > 0),
]),
}
}
return advert
Expand Down
29 changes: 29 additions & 0 deletions src/adverts/advert-mutations/mappers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { mapValues, toLookup } from '../../lib'
import type { TxError, TxResult } from '../../transactions'
import type {
Advert,
AdvertClaim,
AdvertMutationResult,
AdvertMutationStatus,
} from '../types'
Expand Down Expand Up @@ -28,3 +30,30 @@ export const mapTxResultToAdvertMutationResult = (
advert: null,
status: null,
}

export const normalizeAdvertClaims = (claims: AdvertClaim[]): AdvertClaim[] => {
const keyOfClaim = ({ by, type }: AdvertClaim) => `${type}:${by}`

const groups = toLookup(
claims.filter(c => c.quantity > 0),
keyOfClaim
)

const max = <T>(a: T, b: T): T => (b > a ? b : a)

const combined = mapValues<AdvertClaim[], AdvertClaim>(groups, group =>
group.slice(1).reduce(
(agg, c) => ({
...c,
at: max(agg.at, c.at),
quantity: agg.quantity + c.quantity,
}),
group[0]
)
)

return Object.values(combined).sort(({ at: a }, { at: b }) =>
// eslint-disable-next-line no-nested-ternary
a > b ? 1 : a < b ? -1 : 0
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { txBuilder } from '../../../transactions'
import type { Services } from '../../../types'
import { AdvertClaimType, type Advert, type AdvertMutations } from '../../types'
import { mapTxResultToAdvertMutationResult } from '../mappers'
import {
mapTxResultToAdvertMutationResult,
normalizeAdvertClaims,
} from '../mappers'

export const createCancelAdvertReservation =
({
Expand Down Expand Up @@ -30,11 +33,13 @@ export const createCancelAdvertReservation =
)
return {
...advert,
claims: advert.claims // remove all reservations for user
.filter(
({ by, type }) =>
!(by === user.id && type === AdvertClaimType.reserved)
),
claims: normalizeAdvertClaims(
advert.claims // remove all reservations for user
.filter(
({ by, type }) =>
!(by === user.id && type === AdvertClaimType.reserved)
)
),
}
})
.verify(update => update)
Expand Down
9 changes: 6 additions & 3 deletions src/adverts/advert-mutations/reservations/reserve-advert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { txBuilder } from '../../../transactions'
import type { Services } from '../../../types'
import type { Advert, AdvertClaim, AdvertMutations } from '../../types'
import { AdvertClaimType } from '../../types'
import { mapTxResultToAdvertMutationResult } from '../mappers'
import {
mapTxResultToAdvertMutationResult,
normalizeAdvertClaims,
} from '../mappers'
import {
verifyAll,
verifyReservationLimits,
Expand Down Expand Up @@ -36,15 +39,15 @@ export const createReserveAdvert =

return {
...advert,
claims: [
claims: normalizeAdvertClaims([
...advert.claims.filter(a => !isReservedByMe(a)),
{
by: user.id,
at: new Date().toISOString(),
quantity: reservedByMeCount + quantity,
type: AdvertClaimType.reserved,
},
],
]),
}
}
return advert
Expand Down
45 changes: 45 additions & 0 deletions src/adverts/mappers.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { normalizeAdvertClaims } from './advert-mutations/mappers'
import { createEmptyAdvertInput, mapCreateAdvertInputToAdvert } from './mappers'
import { AdvertClaim, AdvertClaimType } from './types'

describe('mapCreateAdvertInputToAdvert', () => {
it('should set input field, user and timestamps', () => {
Expand Down Expand Up @@ -32,3 +34,46 @@ describe('mapCreateAdvertInputToAdvert', () => {
expect(advert.id.length).toBeGreaterThan(32)
})
})

describe('normalizeAdvertsClaims', () => {
const reserve = (claim: Partial<AdvertClaim>): AdvertClaim => ({
by: '',
at: new Date().toDateString(),
type: AdvertClaimType.reserved,
quantity: 1,
...claim,
})
const collect = (claim: Partial<AdvertClaim>): AdvertClaim => ({
by: '',
at: new Date().toDateString(),
type: AdvertClaimType.collected,
quantity: 1,
...claim,
})

it('merges entries by owner and type', () => {
expect(
normalizeAdvertClaims([
reserve({ by: 'a', quantity: 2 }),
collect({ by: 'a' }),
reserve({ by: 'b' }),
reserve({ by: 'a', quantity: 3 }),
])
).toMatchObject([
reserve({ by: 'a', quantity: 5 }),
collect({ by: 'a' }),
reserve({ by: 'b' }),
])
})

it('removes entries with 0 quantity', () => {
expect(
normalizeAdvertClaims([
reserve({ by: 'a', quantity: 0 }),
collect({ by: 'a' }),
reserve({ by: 'b', quantity: 0 }),
reserve({ by: 'a', quantity: 3 }),
])
).toMatchObject([collect({ by: 'a' }), reserve({ by: 'a', quantity: 3 })])
})
})

0 comments on commit 2993fa6

Please sign in to comment.