Skip to content

Commit

Permalink
fix: properly handle polymorphic relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
reegodev committed Feb 1, 2022
1 parent bee94d8 commit 39f6bd3
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 4 deletions.
69 changes: 69 additions & 0 deletions __tests__/serializer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,75 @@ describe('serializer', () => {
})
})

it('serializes a resource with polymorphic relations', async () => {
await expect(async () => {
await serialize(
{
type: 'line_items',

attributes: ['quantity'],

relationships: {
order: 'orders',
item: {
polymorphic: true,
field: 'item_type',
},
line_item_options: 'line_item_options',
shipment_line_items: 'line_items',
stock_transfers: 'stock_transfers',
},
},
{
quantity: 1,
},
{
order: {
id: '12345',
type: 'orders',
},
item: '123456',
},
)
}).rejects.toThrow(
'You must pass a type for relationship "item" because it is polymorphic',
)

const body = await serialize(
{
type: 'line_items',

attributes: ['quantity'],

relationships: {
order: 'orders',
item: {
polymorphic: true,
field: 'item_type',
},
line_item_options: 'line_item_options',
shipment_line_items: 'line_items',
stock_transfers: 'stock_transfers',
},
},
{
quantity: 1,
},
{
order: {
id: '12345',
type: 'orders',
},
item: {
id: '123456',
type: 'adjustments',
},
},
)

expect(body.data.relationships.item.data.type).toEqual('adjustments')
})

it('throws an error with invalid attributes', async () => {
await expect(async () => {
await serialize(
Expand Down
7 changes: 6 additions & 1 deletion src/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ import {
} from './api'
import { getType, isObject } from './utils'

export interface PolymorphicRelationship {
polymorphic: true
field: string
}

export interface ResourceConfig<T, U> {
type: string
attributes: (keyof T)[]
relationships: Record<keyof U, string>
relationships: Record<keyof U, string | PolymorphicRelationship>
}

export interface CommonResourceAttributes {
Expand Down
22 changes: 19 additions & 3 deletions src/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ResourceConfig,
AttributesPayload,
RelationshipsPayload,
PolymorphicRelationship,
} from './resource'
import { getType, isObject } from './utils'

Expand Down Expand Up @@ -84,10 +85,15 @@ export const serialize = async <T, U>(
//
relationshipKeys.forEach((relationshipKey) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const configRelationships: Record<string, any> = config.relationships
const configRelationships: Record<
string,
string | PolymorphicRelationship
> = config.relationships

const relationshipTypeConfig = configRelationships[relationshipKey]

// Only add relationships supported by the config
if (configRelationships[relationshipKey]) {
if (relationshipTypeConfig) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const relationshipValue = (relationships as any)[relationshipKey] || {
id: null,
Expand All @@ -99,9 +105,19 @@ export const serialize = async <T, U>(
)
}

if (
typeof relationshipTypeConfig === 'object' &&
relationshipTypeConfig.polymorphic &&
(typeof relationshipValue === 'string' || !relationshipValue.type)
) {
throw new Error(
`You must pass a type for relationship "${relationshipKey}" because it is polymorphic`,
)
}

serialized.data.relationships[relationshipKey] = {
data: {
type: configRelationships[relationshipKey],
type: relationshipValue.type ?? relationshipTypeConfig,
// Support passing a relationship as id or as a full object
id:
typeof relationshipValue === 'string'
Expand Down

0 comments on commit 39f6bd3

Please sign in to comment.