Skip to content

Commit

Permalink
custom obj translation refrence fields and validation rules
Browse files Browse the repository at this point in the history
  • Loading branch information
hadard committed Mar 11, 2020
1 parent 0f772a9 commit 2dda8ca
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 8 deletions.
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"salto-vscode/**"
]
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/salesforce-adapter/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export const TOPICS_FOR_OBJECTS_METADATA_TYPE = 'TopicsForObjects'
export const PROFILE_METADATA_TYPE = 'Profile'
export const WORKFLOW_METADATA_TYPE = 'Workflow'
export const ASSIGNMENT_RULES_METADATA_TYPE = 'AssignmentRules'
export const VALIDATION_RULES_METADATA_TYPE = 'ValidationRule'
export const LEAD_CONVERT_SETTINGS_METADATA_TYPE = 'LeadConvertSettings'
export const QUICK_ACTION_METADATA_TYPE = 'QuickAction'
export const CUSTOM_TAB_METADATA_TYPE = 'CustomTab'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2020 Salto Labs Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import wu from 'wu'
import {
Element, ElemID, findInstances, InstanceElement,
} from '@salto-io/adapter-api'
import { collections } from '@salto-io/lowerdash'
import _ from 'lodash'
import { FilterWith } from '../filter'
import { generateApiNameToCustomObject, apiNameParts, getInstancesOfMetadataType } from './utils'
import { SALESFORCE, CUSTOM_OBJECT_TRANSLATION_METADATA_TYPE, VALIDATION_RULES_METADATA_TYPE } from '../constants'

const { makeArray } = collections.array

export const CUSTOM_OBJ_METADATA_TYPE_ID = new ElemID(SALESFORCE,
CUSTOM_OBJECT_TRANSLATION_METADATA_TYPE)

const FIELDS = 'fields'
const NAME = 'name'
const VALIDATION_RULES = 'validationRules'

/**
* This filter change CustomObjectTranslation logical references to fields and validation rules to
* Salto referenes
*/
const filterCreator = (): FilterWith<'onFetch'> => ({
onFetch: async (elements: Element[]) => {
const ruleObj = (rule: InstanceElement): string => apiNameParts(rule)[0]
const ruleShortName = (rule: InstanceElement): string => apiNameParts(rule)[1]

const apiNameToCustomObject = generateApiNameToCustomObject(elements)
const apiNameToRules = _.groupBy(
getInstancesOfMetadataType(elements, VALIDATION_RULES_METADATA_TYPE),
ruleObj
)

wu(findInstances(elements, CUSTOM_OBJ_METADATA_TYPE_ID))
.forEach(customTranslation => {
const customObjApiName = apiNameParts(customTranslation)[0]

// Change fields to reference
const customObj = apiNameToCustomObject.get(customObjApiName)
makeArray(customTranslation.value[FIELDS]).forEach(field => {
const customField = customObj?.fields[field[NAME]]
if (customField) {
field[NAME] = customField.elemID
}
})

// Change validation rules to refs
const objRules = apiNameToRules[customObjApiName]
makeArray(customTranslation.value[VALIDATION_RULES]).forEach(rule => {
const ruleInstance = objRules?.find(r => _.isEqual(ruleShortName(r), rule[NAME]))
if (ruleInstance) {
rule[NAME] = ruleInstance.elemID
}
})
})
},
})

export default filterCreator
8 changes: 3 additions & 5 deletions packages/salesforce-adapter/src/filters/custom_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
FORMULA, LEAD_CONVERT_SETTINGS_METADATA_TYPE, ASSIGNMENT_RULES_METADATA_TYPE,
WORKFLOW_METADATA_TYPE, QUICK_ACTION_METADATA_TYPE, CUSTOM_TAB_METADATA_TYPE,
DUPLICATE_RULE_METADATA_TYPE, CUSTOM_OBJECT_TRANSLATION_METADATA_TYPE,
VALIDATION_RULES_METADATA_TYPE,
} from '../constants'
import { FilterCreator } from '../filter'
import {
Expand All @@ -39,7 +40,7 @@ import {
} from '../transformers/transformer'
import {
id, addApiName, addMetadataType, addLabel, hasNamespace, getNamespace, boolValue,
buildAnnotationsObjectType, generateApiNameToCustomObject, addObjectParentReference,
buildAnnotationsObjectType, generateApiNameToCustomObject, addObjectParentReference, apiNameParts,
} from './utils'
import { convertList } from './convert_lists'

Expand All @@ -63,7 +64,7 @@ export const NESTED_INSTANCE_VALUE_NAME = {

export const NESTED_INSTANCE_TYPE_NAME = {
WEB_LINK: 'WebLink',
VALIDATION_RULE: 'ValidationRule',
VALIDATION_RULE: VALIDATION_RULES_METADATA_TYPE,
BUSINESS_PROCESS: 'BusinessProcess',
RECORD_TYPE: 'RecordType',
LIST_VIEW: 'ListView',
Expand Down Expand Up @@ -476,9 +477,6 @@ const hasCustomObjectParent = (instance: InstanceElement): boolean =>


const fixDependentInstancesPathAndSetParent = (elements: Element[]): void => {
const apiNameParts = (instance: InstanceElement): string[] =>
apiName(instance).split(/\.|-/g)

const setDependingInstancePath = (instance: InstanceElement, customObject: ObjectType):
void => {
if (customObject.path) {
Expand Down
3 changes: 3 additions & 0 deletions packages/salesforce-adapter/src/filters/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ export const buildAnnotationsObjectType = (annotationTypes: TypeMap): ObjectType
export const generateApiNameToCustomObject = (elements: Element[]): Map<string, ObjectType> =>
new Map(getCustomObjects(elements).map(obj => [apiName(obj), obj]))

export const apiNameParts = (instance: InstanceElement): string[] =>
apiName(instance).split(/\.|-/g)

export const addObjectParentReference = (instance: InstanceElement,
{ elemID: objectID }: ObjectType): void => {
const instanceDeps = makeArray(instance.annotations[INSTANCE_ANNOTATIONS.PARENT])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 2020 Salto Labs Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import _ from 'lodash'
import {
ObjectType, InstanceElement, Field, BuiltinTypes, ElemID,
} from '@salto-io/adapter-api'
import filterCreator from '../../src/filters/custom_object_translation'
import {
SALESFORCE, CUSTOM_OBJECT_TRANSLATION_METADATA_TYPE, METADATA_TYPE, CUSTOM_OBJECT, API_NAME,
VALIDATION_RULES_METADATA_TYPE,
INSTANCE_FULL_NAME_FIELD,
} from '../../src/constants'
import { FilterWith } from '../../src/filter'

describe('custom object translation filter', () => {
const customObjName = 'MockCustomObject'
const customFieldName = 'MockField'
const customObjElemID = new ElemID(SALESFORCE, customObjName)
const customObject = new ObjectType(
{
elemID: customObjElemID,
fields: {
[customFieldName]: new Field(customObjElemID, customFieldName, BuiltinTypes.STRING),
},
annotations: {
[METADATA_TYPE]: CUSTOM_OBJECT,
[API_NAME]: customObjName,
},
}
)
const validationRuleName = 'Last_Price'
const validationRuleType = new ObjectType({
elemID: new ElemID(SALESFORCE, VALIDATION_RULES_METADATA_TYPE),
annotations: { [METADATA_TYPE]: VALIDATION_RULES_METADATA_TYPE },
})
const validationRuleInstance = new InstanceElement(
`${customObjName}_${validationRuleName}`,
validationRuleType,
{ [INSTANCE_FULL_NAME_FIELD]: `${customObjName}.${validationRuleName}` }
)
const objTranslationType = new ObjectType({
elemID: new ElemID(SALESFORCE, CUSTOM_OBJECT_TRANSLATION_METADATA_TYPE),
})
const objTranslationInstance = new InstanceElement(
`${customObjName}-en_US`,
objTranslationType,
{
[INSTANCE_FULL_NAME_FIELD]: `${customObjName}-en_US`,
fields: [{ name: customFieldName }, { name: 'not-exists' }],
validationRules: [{ name: validationRuleName }, { name: 'not-exists' }],
},
)

describe('on fetch', () => {
let postFilter: InstanceElement

beforeAll(async () => {
const filter = filterCreator() as FilterWith<'onFetch'>
const testElements = [
_.clone(objTranslationInstance),
_.clone(customObject),
_.clone(objTranslationType),
_.clone(validationRuleType),
_.clone(validationRuleInstance),
]
await filter.onFetch(testElements)
postFilter = testElements[0] as InstanceElement
})

describe('fields reference', () => {
it('should transform fields to reference', async () => {
expect(postFilter.value.fields[0].name)
.toEqual(customObject.fields[customFieldName].elemID)
})
it('should keep name as is if no referenced field was found', async () => {
expect(postFilter.value.fields[1].name).toBe('not-exists')
})
})

describe('validation rules reference', () => {
it('should transform validation rules to reference', async () => {
expect(postFilter.value.validationRules[0].name)
.toEqual(validationRuleInstance.elemID)
})
it('should keep name as is if no referenced validation rules was found', async () => {
expect(postFilter.value.validationRules[1].name).toBe('not-exists')
})
})
})
})

0 comments on commit 2dda8ca

Please sign in to comment.