Skip to content

Commit

Permalink
sync actions for attribute group (#1876)
Browse files Browse the repository at this point in the history
* feat: add sync actions for attribute group

* chore: add changeset
  • Loading branch information
jaikumar-tj committed Jul 20, 2023
1 parent 470456f commit 27f0d2b
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/tough-turkeys-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@commercetools/sync-actions': minor
---

Add support for attribute groups `changeName`, `setKey`, `setDescription`, `addAttribute` and `removeAttribute` actions.
65 changes: 65 additions & 0 deletions packages/sync-actions/src/attribute-groups-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { buildBaseAttributesActions } from './utils/common-actions'
import createBuildArrayActions, {
ADD_ACTIONS,
REMOVE_ACTIONS,
CHANGE_ACTIONS,
} from './utils/create-build-array-actions'

const hasAttribute = (attributes, newValue) =>
attributes.some((attribute) => attribute.key === newValue.key)

export const baseActionsList = [
{ action: 'changeName', key: 'name' },
{ action: 'setKey', key: 'key' },
{ action: 'setDescription', key: 'description' },
]

export function actionsMapBase(diff, oldObj, newObj, config = {}) {
return buildBaseAttributesActions({
actions: baseActionsList,
diff,
oldObj,
newObj,
shouldOmitEmptyString: config.shouldOmitEmptyString,
})
}

export function actionsMapAttributes(diff, oldObj, newObj) {
const handler = createBuildArrayActions('attributes', {
[ADD_ACTIONS]: (newAttribute) => ({
action: 'addAttribute',
attribute: newAttribute,
}),
[REMOVE_ACTIONS]: (oldAttribute) => {
// We only add the action if the attribute is not included in the new object.
return !hasAttribute(newObj.attributes, oldAttribute)
? {
action: 'removeAttribute',
attribute: oldAttribute,
}
: null
},
[CHANGE_ACTIONS]: (oldAttribute, newAttribute) => {
const result = []
// We only remove the attribute in case that the oldAttribute is not
// included in the new object
if (!hasAttribute(newObj.attributes, oldAttribute))
result.push({
action: 'removeAttribute',
attribute: oldAttribute,
})

// We only add the attribute in case that the newAttribute was not
// included in the old object
if (!hasAttribute(oldObj.attributes, newAttribute))
result.push({
action: 'addAttribute',
attribute: newAttribute,
})

return result
},
})

return handler(diff, oldObj, newObj)
}
59 changes: 59 additions & 0 deletions packages/sync-actions/src/attribute-groups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* @flow */
import flatten from 'lodash.flatten'
import type {
SyncAction,
ActionGroup,
UpdateAction,
SyncActionConfig,
} from 'types/sdk'
import * as attributeGroupsActions from './attribute-groups-actions'
import createBuildActions from './utils/create-build-actions'
import createMapActionGroup from './utils/create-map-action-group'
import * as diffpatcher from './utils/diffpatcher'

function createAttributeGroupsMapActions(
mapActionGroup: (
type: string,
fn: () => Array<UpdateAction>
) => Array<UpdateAction>,
syncActionConfig: SyncActionConfig
): (diff: Object, newObj: Object, oldObj: Object) => Array<UpdateAction> {
return function doMapActions(
diff: Object,
newObj: Object,
oldObj: Object
): Array<UpdateAction> {
const allActions = []
allActions.push(
mapActionGroup('base', (): Array<UpdateAction> =>
attributeGroupsActions.actionsMapBase(
diff,
oldObj,
newObj,
syncActionConfig
)
)
)
allActions.push(
flatten(
mapActionGroup('attributes', (): Array<UpdateAction> =>
attributeGroupsActions.actionsMapAttributes(diff, oldObj, newObj)
)
)
)
return flatten(allActions)
}
}

export default (
actionGroupList: Array<ActionGroup>,
syncActionConfig: SyncActionConfig
): SyncAction => {
const mapActionGroup = createMapActionGroup(actionGroupList)
const doMapActions = createAttributeGroupsMapActions(
mapActionGroup,
syncActionConfig
)
const buildActions = createBuildActions(diffpatcher.diff, doMapActions)
return { buildActions }
}
1 change: 1 addition & 0 deletions packages/sync-actions/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export { default as createSyncProjects } from './projects'
export { default as createSyncStores } from './stores'
export { default as createSyncProductSelections } from './product-selections'
export { default as createSyncStandalonePrices } from './prices'
export { default as createSyncAttributeGroups } from './attribute-groups'
205 changes: 205 additions & 0 deletions packages/sync-actions/test/attribute-groups-sync.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import attributeGroupSyncFn from '../src/attribute-groups'
import { baseActionsList } from '../src/attribute-groups-actions'

describe('Exports', () => {
test('correctly define base actions list', () => {
expect(baseActionsList).toEqual([
{ action: 'changeName', key: 'name' },
{ action: 'setKey', key: 'key' },
{ action: 'setDescription', key: 'description' },
])
})
})

describe('Actions', () => {
let attributeGroupSync
beforeEach(() => {
attributeGroupSync = attributeGroupSyncFn()
})

test('should build `changeName` action', () => {
const before = {
name: 'John',
}
const now = {
name: 'Robert',
}

const actual = attributeGroupSync.buildActions(now, before)
const expected = [{ action: 'changeName', name: now.name }]
expect(actual).toEqual(expected)
})

test('should build `setDescription` action', () => {
const before = {
description: 'some description',
}
const now = {
description: 'some updated description',
}

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{
action: 'setDescription',
description: now.description,
},
]
expect(actual).toEqual(expected)
})

test('should build `setKey` action', () => {
const before = {
key: 'some-key',
}
const now = {
key: 'new-key',
}

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{
action: 'setKey',
key: now.key,
},
]
expect(actual).toEqual(expected)
})

describe('`addAttribute`', () => {
test('should build `addAttribute` action with one attribute', () => {
const before = {
attributes: [],
}
const now = { attributes: [{ key: 'Size' }] }

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'addAttribute', attribute: now.attributes[0] },
]
expect(actual).toEqual(expected)
})
test('should build `addAttribute` action with two attributes', () => {
const before = { attributes: [] }
const now = { attributes: [{ key: 'Size' }, { key: 'Brand' }] }

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'addAttribute', attribute: now.attributes[0] },
{ action: 'addAttribute', attribute: now.attributes[1] },
]
expect(actual).toEqual(expected)
})
})

describe('`removeAttribute`', () => {
test('should build `removeAttribute` action removing one attribute', () => {
const before = {
attributes: [{ key: 'Size' }, { key: 'Brand' }],
}
const now = { attributes: [{ key: 'Size' }] }

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'removeAttribute', attribute: before.attributes[1] },
]
expect(actual).toEqual(expected)
})
test('should build `removeAttribute` action removing two attributes', () => {
const before = {
attributes: [{ key: 'Size' }, { key: 'Brand' }],
}
const now = { attributes: [] }

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'removeAttribute', attribute: before.attributes[0] },
{ action: 'removeAttribute', attribute: before.attributes[1] },
]
expect(actual).toEqual(expected)
})
})

describe('Swap attributes (create one + delete one)', () => {
test('should build `removeAttribute` and `addAttribute`', () => {
const before = { attributes: [{ key: 'Size' }] }
const now = { attributes: [{ key: 'Brand' }] }

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'removeAttribute', attribute: before.attributes[0] },
{ action: 'addAttribute', attribute: now.attributes[0] },
]
expect(actual).toEqual(expected)
})
})

describe('Multiple actions', () => {
test('should build multiple actions for required changes', () => {
const before = {
attributes: [{ key: 'Size' }, { key: 'Brand' }],
}
const now = {
attributes: [{ key: 'Quality' }, { key: 'Brand' }, { key: 'color' }],
}

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'removeAttribute', attribute: before.attributes[0] },
{ action: 'addAttribute', attribute: now.attributes[0] },
{ action: 'addAttribute', attribute: now.attributes[2] },
]
expect(actual).toEqual(expected)
})
})

describe('Delete first attributes', () => {
test('should build multiple actions for required changes', () => {
const before = {
attributes: [{ key: 'Size' }, { key: 'Brand' }, { key: 'Color' }],
}
const now = {
attributes: [{ key: 'Color' }],
}

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'removeAttribute', attribute: before.attributes[0] },
{ action: 'removeAttribute', attribute: before.attributes[1] },
]
expect(actual).toEqual(expected)
})
})

describe('Delete multiple attributes', () => {
test('should build multiple actions for required changes', () => {
const before = {
attributes: [
{ key: 'Size' },
{ key: 'Brand' },
{ key: 'Quality' },
{ key: 'Color' },
{ key: 'Model' },
{ key: 'attr-1' },
],
}
const now = {
attributes: [
{ key: 'Brand' },
{ key: 'Quality' },
{ key: 'Model' },
{ key: 'attr-2' },
],
}

const actual = attributeGroupSync.buildActions(now, before)
const expected = [
{ action: 'removeAttribute', attribute: before.attributes[0] },
{ action: 'removeAttribute', attribute: before.attributes[3] },
{ action: 'addAttribute', attribute: now.attributes[3] },
{ action: 'removeAttribute', attribute: before.attributes[5] },
]
expect(actual).toEqual(expected)
})
})
})

0 comments on commit 27f0d2b

Please sign in to comment.