mcdev 8.2.1 → 8.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/.github/workflows/code-test.yml +1 -1
- package/.github/workflows/coverage-base-update.yml +1 -1
- package/.github/workflows/coverage-develop-branch.yml +1 -1
- package/.github/workflows/coverage-main-branch.yml +1 -1
- package/.github/workflows/coverage.yml +1 -1
- package/.github/workflows/npm-publish.yml +7 -5
- package/@types/lib/MetadataTypeDefinitions.d.ts +4 -0
- package/@types/lib/MetadataTypeDefinitions.d.ts.map +1 -1
- package/@types/lib/MetadataTypeInfo.d.ts +4 -0
- package/@types/lib/MetadataTypeInfo.d.ts.map +1 -1
- package/@types/lib/Retriever.d.ts.map +1 -1
- package/@types/lib/index.d.ts +20 -9
- package/@types/lib/index.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Asset.d.ts +3 -3
- package/@types/lib/metadataTypes/Asset.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Automation.d.ts +7 -7
- package/@types/lib/metadataTypes/Automation.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtension.d.ts +9 -9
- package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtensionField.d.ts +7 -0
- package/@types/lib/metadataTypes/DataExtensionField.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataFilter.d.ts +335 -0
- package/@types/lib/metadataTypes/DataFilter.d.ts.map +1 -0
- package/@types/lib/metadataTypes/DataFilterHidden.d.ts +164 -0
- package/@types/lib/metadataTypes/DataFilterHidden.d.ts.map +1 -0
- package/@types/lib/metadataTypes/Filter.d.ts +181 -6
- package/@types/lib/metadataTypes/Filter.d.ts.map +1 -1
- package/@types/lib/metadataTypes/FilterDefinition.d.ts +318 -0
- package/@types/lib/metadataTypes/FilterDefinition.d.ts.map +1 -0
- package/@types/lib/metadataTypes/FilterDefinitionHidden.d.ts +156 -0
- package/@types/lib/metadataTypes/FilterDefinitionHidden.d.ts.map +1 -0
- package/@types/lib/metadataTypes/ImportFile.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Journey.d.ts +18 -0
- package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MetadataType.d.ts +6 -0
- package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MobileKeyword.d.ts +2 -2
- package/@types/lib/metadataTypes/MobileKeyword.d.ts.map +1 -1
- package/@types/lib/metadataTypes/User.d.ts +1 -1
- package/@types/lib/metadataTypes/User.d.ts.map +1 -1
- package/@types/lib/metadataTypes/definitions/DataFilter.definition.d.ts +230 -0
- package/@types/lib/metadataTypes/definitions/DataFilter.definition.d.ts.map +1 -0
- package/@types/lib/metadataTypes/definitions/DataFilterHidden.definition.d.ts +230 -0
- package/@types/lib/metadataTypes/definitions/DataFilterHidden.definition.d.ts.map +1 -0
- package/@types/lib/metadataTypes/definitions/Filter.definition.d.ts +203 -31
- package/@types/lib/metadataTypes/definitions/FilterDefinition.definition.d.ts +218 -0
- package/@types/lib/metadataTypes/definitions/FilterDefinition.definition.d.ts.map +1 -0
- package/@types/lib/metadataTypes/definitions/FilterDefinitionHidden.definition.d.ts +218 -0
- package/@types/lib/metadataTypes/definitions/FilterDefinitionHidden.definition.d.ts.map +1 -0
- package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +18 -0
- package/@types/lib/util/devops.d.ts +1 -0
- package/@types/lib/util/devops.d.ts.map +1 -1
- package/@types/lib/util/replaceContentBlockReference.d.ts +3 -3
- package/@types/lib/util/replaceContentBlockReference.d.ts.map +1 -1
- package/@types/lib/util/util.d.ts.map +1 -1
- package/@types/lib/util/validations.d.ts.map +1 -1
- package/@types/types/mcdev.d.d.ts +296 -0
- package/@types/types/mcdev.d.d.ts.map +1 -1
- package/lib/MetadataTypeDefinitions.js +4 -0
- package/lib/MetadataTypeInfo.js +4 -0
- package/lib/Retriever.js +3 -0
- package/lib/index.js +87 -3
- package/lib/metadataTypes/DataExtensionField.js +21 -0
- package/lib/metadataTypes/DataFilter.js +694 -0
- package/lib/metadataTypes/DataFilterHidden.js +18 -0
- package/lib/metadataTypes/Filter.js +315 -1
- package/lib/metadataTypes/ImportFile.js +11 -1
- package/lib/metadataTypes/Journey.js +111 -7
- package/lib/metadataTypes/MetadataType.js +14 -0
- package/lib/metadataTypes/definitions/Automation.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataFilter.definition.js +168 -0
- package/lib/metadataTypes/definitions/DataFilterHidden.definition.js +169 -0
- package/lib/metadataTypes/definitions/Filter.definition.js +136 -22
- package/lib/metadataTypes/definitions/Journey.definition.js +20 -1
- package/lib/util/devops.js +14 -4
- package/lib/util/util.js +7 -2
- package/lib/util/validations.js +7 -1
- package/package.json +10 -10
- package/test/general.test.js +17 -19
- package/test/mockRoot/.mcdevrc.json +4 -1
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-fail.asset-block-meta.json → testExisting_asset_html-matchNamFail.asset-block-meta.json} +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName.asset-block-meta.json → testExisting_asset_html-matchName.asset-block-meta.json} +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-create.asset-block-meta.json → testExisting_asset_html-matchNameAdd.asset-block-meta.json} +3 -3
- package/test/mockRoot/deploy/testInstance/testBU/dataFilter/testExisting_dataFilter.dataFilter-meta.json +19 -0
- package/test/mockRoot/deploy/testInstance/testBU/dataFilter/testNew_dataFilter.dataFilter-meta.json +19 -0
- package/test/mockRoot/deploy/testInstance/testBU/filter/testExisting_filter.filter-meta.json +10 -0
- package/test/mockRoot/deploy/testInstance/testBU/filter/testNew_filter.filter-meta.json +11 -0
- package/test/mockRoot/deploy/testInstance/testBU/journey/testExisting_journey_updatecontact.journey-meta.json +108 -0
- package/test/resources/9999999/asset/v1/content/assets/1295064/patch-response.json +1 -1
- package/test/resources/9999999/automation/v1/filters/a0f1a1bc-4ea1-44b3-8fe1-ce40ef35c1c0/patch-response.json +18 -0
- package/test/resources/9999999/automation/v1/filters/f018f237-f7ef-40b0-afc8-39ea2e5dcca4/delete-response.txt +0 -0
- package/test/resources/9999999/automation/v1/filters/f018f237-f7ef-40b0-afc8-39ea2e5dcca4/get-response.json +15 -0
- package/test/resources/9999999/automation/v1/filters/f018f237-f7ef-40b0-afc8-39ea2e5dcca4/patch-response.json +15 -0
- package/test/resources/9999999/automation/v1/filters/get-response.json +22 -0
- package/test/resources/9999999/dataFilter/build-expected.json +19 -0
- package/test/resources/9999999/dataFilter/get-expected.json +23 -0
- package/test/resources/9999999/dataFilter/patch-expected.json +20 -0
- package/test/resources/9999999/dataFilter/post-expected.json +20 -0
- package/test/resources/9999999/dataFilter/template-expected.json +19 -0
- package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-sha,automatio,cloudpage,dataexten,filteract,filterdef,hidden,journey,list,mysubs,publicati,queryacti,salesforc,shared_da,shared_da,shared_sa,ssjsactiv,synchroni,useriniti-response.xml +765 -0
- package/test/resources/9999999/dataFolder/retrieve-ContentTypeINfilteractivity,hidden-response.xml +139 -0
- package/test/resources/9999999/dataFolder/retrieve-ContentTypeINfilterdefinition,hidden-response.xml +116 -0
- package/test/resources/9999999/email/v1/filters/filterdefinition/10ef27dd-4be8-4bf6-970a-8acf8e281e55/delete-response.txt +1 -0
- package/test/resources/9999999/email/v1/filters/filterdefinition/10ef27dd-4be8-4bf6-970a-8acf8e281e55/get-response.json +19 -0
- package/test/resources/9999999/email/v1/filters/filterdefinition/10ef27dd-4be8-4bf6-970a-8acf8e281e55/patch-response.json +15 -0
- package/test/resources/9999999/email/v1/filters/filterdefinition/category/5318/get-response.json +27 -0
- package/test/resources/9999999/email/v1/filters/filterdefinition/category/8502/get-response.json +7 -0
- package/test/resources/9999999/email/v1/filters/filterdefinition/category/8503/get-response.json +7 -0
- package/test/resources/9999999/email/v1/filters/filterdefinition/post-response.json +15 -0
- package/test/resources/9999999/filter/build-expected.json +10 -0
- package/test/resources/9999999/filter/get-expected.json +11 -0
- package/test/resources/9999999/filter/patch-expected.json +11 -0
- package/test/resources/9999999/filter/post-expected.json +11 -0
- package/test/resources/9999999/filter/template-expected.json +10 -0
- package/test/resources/9999999/filterActivity/create-response.xml +46 -0
- package/test/resources/9999999/filterActivity/retrieve-CustomerKey=testExisting_filter-response.xml +30 -0
- package/test/resources/9999999/filterDefinition/retrieve-CustomerKey=testExisting_dataFilter-response.xml +30 -0
- package/test/resources/9999999/interaction/v1/interactions/get-response.json +45 -3
- package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_updatecontact/get-response.json +119 -0
- package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_updatecontact/put-response.json +106 -0
- package/test/resources/9999999/journey/get-updatecontact-expected.json +108 -0
- package/test/resources/9999999/journey/put-updatecontact-expected.json +108 -0
- package/test/type.asset.test.js +7 -7
- package/test/type.automation.test.js +14 -14
- package/test/type.dataFilter.test.js +174 -0
- package/test/type.filter.test.js +170 -0
- package/test/type.journey.test.js +59 -7
- package/test/type.query.test.js +2 -2
- package/test/utils.js +8 -0
- package/types/mcdev.d.js +101 -0
- /package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-create.asset-block-meta.html → testExisting_asset_html-matchNamFail.asset-block-meta.html} +0 -0
- /package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-fail.asset-block-meta.html → testExisting_asset_html-matchName.asset-block-meta.html} +0 -0
- /package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName.asset-block-meta.html → testExisting_asset_html-matchNameAdd.asset-block-meta.html} +0 -0
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import MetadataType from './MetadataType.js';
|
|
4
|
+
import { Util } from '../util/util.js';
|
|
5
|
+
import cache from '../util/cache.js';
|
|
6
|
+
import DataExtensionField from './DataExtensionField.js';
|
|
7
|
+
import Folder from './Folder.js';
|
|
8
|
+
import { XMLBuilder, XMLParser } from 'fast-xml-parser';
|
|
9
|
+
import File from '../util/file.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {import('../../types/mcdev.d.js').BuObject} BuObject
|
|
13
|
+
* @typedef {import('../../types/mcdev.d.js').CodeExtract} CodeExtract
|
|
14
|
+
* @typedef {import('../../types/mcdev.d.js').CodeExtractItem} CodeExtractItem
|
|
15
|
+
* @typedef {import('../../types/mcdev.d.js').MetadataTypeItem} MetadataTypeItem
|
|
16
|
+
* @typedef {import('../../types/mcdev.d.js').MetadataTypeItemDiff} MetadataTypeItemDiff
|
|
17
|
+
* @typedef {import('../../types/mcdev.d.js').MetadataTypeItemObj} MetadataTypeItemObj
|
|
18
|
+
* @typedef {import('../../types/mcdev.d.js').MetadataTypeMap} MetadataTypeMap
|
|
19
|
+
* @typedef {import('../../types/mcdev.d.js').MetadataTypeMapObj} MetadataTypeMapObj
|
|
20
|
+
* @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams
|
|
21
|
+
* @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap
|
|
22
|
+
* @typedef {import('../../types/mcdev.d.js').DataFilterItem} DataFilterItem
|
|
23
|
+
* @typedef {import('../../types/mcdev.d.js').DataExtensionFieldMap} DataExtensionFieldMap
|
|
24
|
+
* @typedef {import('../../types/mcdev.d.js').DataExtensionFieldItem} DataExtensionFieldItem
|
|
25
|
+
* @typedef {import('../../types/mcdev.d.js').DataFilterMap} DataFilterMap
|
|
26
|
+
* @typedef {import('../../types/mcdev.d.js').MultiMetadataTypeMap} MultiMetadataTypeMap
|
|
27
|
+
* @typedef {import('../../types/mcdev.d.js').FilterConditionSet} FilterConditionSet
|
|
28
|
+
* @typedef {import('../../types/mcdev.d.js').FilterCondition} FilterCondition
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* DataFilter (FilterDefinition) MetadataType
|
|
33
|
+
*
|
|
34
|
+
* @augments MetadataType
|
|
35
|
+
*/
|
|
36
|
+
class DataFilter extends MetadataType {
|
|
37
|
+
static cache = {}; // type internal cache for various things
|
|
38
|
+
static deIdKeyMap;
|
|
39
|
+
static hidden = false;
|
|
40
|
+
/**
|
|
41
|
+
* Retrieves all records and saves it to disk
|
|
42
|
+
*
|
|
43
|
+
* @param {string} retrieveDir Directory where retrieved metadata directory will be saved
|
|
44
|
+
* @param {string[]} [_] unused parameter
|
|
45
|
+
* @param {string[]} [__] unused parameter
|
|
46
|
+
* @param {string} [key] customer key of single item to retrieve
|
|
47
|
+
* @returns {Promise.<{metadata: DataFilterMap, type: string}>} Promise of items
|
|
48
|
+
*/
|
|
49
|
+
static async retrieve(retrieveDir, _, __, key) {
|
|
50
|
+
Util.logBeta(this.definition.type);
|
|
51
|
+
/** @type {DataFilterMap} */
|
|
52
|
+
const filterDefinitionMap = {};
|
|
53
|
+
|
|
54
|
+
const objectId = key ? await this._getObjectIdForSingleRetrieve(key) : null;
|
|
55
|
+
if (objectId) {
|
|
56
|
+
const metadataMapSingle = await super.retrieveREST(
|
|
57
|
+
null,
|
|
58
|
+
'/email/v1/filters/filterdefinition/' + objectId,
|
|
59
|
+
null,
|
|
60
|
+
key
|
|
61
|
+
);
|
|
62
|
+
Object.assign(filterDefinitionMap, metadataMapSingle.metadata);
|
|
63
|
+
} else {
|
|
64
|
+
const filterFolders = await this._getFilterFolderIds();
|
|
65
|
+
|
|
66
|
+
for (const folderId of filterFolders) {
|
|
67
|
+
const metadataMapFolder = await super.retrieveREST(
|
|
68
|
+
null,
|
|
69
|
+
'email/v1/filters/filterdefinition/category/' +
|
|
70
|
+
folderId +
|
|
71
|
+
'?derivedFromType=1,2,3,4&',
|
|
72
|
+
null,
|
|
73
|
+
key
|
|
74
|
+
);
|
|
75
|
+
if (Object.keys(metadataMapFolder.metadata).length) {
|
|
76
|
+
Object.assign(filterDefinitionMap, metadataMapFolder.metadata);
|
|
77
|
+
if (filterDefinitionMap[key]) {
|
|
78
|
+
// if key was found we can stop checking other folders
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// /** @type {DataFilterMap} */
|
|
85
|
+
// const filterDefinitionMap = metadataTypeMapObj.metadata;
|
|
86
|
+
for (const item of Object.values(filterDefinitionMap)) {
|
|
87
|
+
// description is not returned when empty
|
|
88
|
+
item.description ||= '';
|
|
89
|
+
}
|
|
90
|
+
if (retrieveDir) {
|
|
91
|
+
// custom dataExtensionField caching
|
|
92
|
+
await this._cacheDeFields(filterDefinitionMap, 'retrieve');
|
|
93
|
+
// await this._cacheContactAttributes(filterDefinitionMap);
|
|
94
|
+
// await this._cacheMeasures(filterDefinitionMap);
|
|
95
|
+
|
|
96
|
+
const savedMetadata = await this.saveResults(filterDefinitionMap, retrieveDir);
|
|
97
|
+
Util.logger.info(
|
|
98
|
+
`Downloaded: ${this.definition.type} (${Object.keys(savedMetadata).length})` +
|
|
99
|
+
Util.getKeysString(key)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { metadata: filterDefinitionMap, type: this.definition.type };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* helper for {@link DataFilter.retrieve}
|
|
107
|
+
*
|
|
108
|
+
* @param {boolean} [recached] indicates if this is a recursive call after cache refresh
|
|
109
|
+
* @returns {Promise.<number[]>} Array of folder IDs
|
|
110
|
+
*/
|
|
111
|
+
static async _getFilterFolderIds(recached = false) {
|
|
112
|
+
const fromCache =
|
|
113
|
+
this.cache.folderFilter || cache.getCache().folder
|
|
114
|
+
? Object.values(this.cache.folderFilter || cache.getCache().folder)
|
|
115
|
+
.filter((item) => item.ContentType === 'filterdefinition')
|
|
116
|
+
.filter(
|
|
117
|
+
(item) =>
|
|
118
|
+
(!this.hidden && item.Path.startsWith('Data Filters')) ||
|
|
119
|
+
(this.hidden && !item.Path.startsWith('Data Filters'))
|
|
120
|
+
) // only retrieve from Data Filters folder
|
|
121
|
+
.map((item) => item.ID)
|
|
122
|
+
: [];
|
|
123
|
+
if (fromCache.length) {
|
|
124
|
+
return fromCache;
|
|
125
|
+
}
|
|
126
|
+
if (recached) {
|
|
127
|
+
Util.logger.debug('_getFilterFolderIds: could not find filterdefinition folders');
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const subTypeArr = ['hidden', 'filterdefinition'];
|
|
132
|
+
Util.logger.info(` - Caching dependent Metadata: folder`);
|
|
133
|
+
Util.logSubtypes(subTypeArr);
|
|
134
|
+
|
|
135
|
+
Folder.client = this.client;
|
|
136
|
+
Folder.buObject = this.buObject;
|
|
137
|
+
Folder.properties = this.properties;
|
|
138
|
+
this.cache.folderFilter = (await Folder.retrieveForCache(null, subTypeArr)).metadata;
|
|
139
|
+
return this._getFilterFolderIds(true);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* helper for {@link DataFilter._cacheMeasures}
|
|
143
|
+
*
|
|
144
|
+
* @returns {Promise.<number[]>} Array of folder IDs
|
|
145
|
+
*/
|
|
146
|
+
static async _getMeasureFolderIds() {
|
|
147
|
+
const fromCache =
|
|
148
|
+
this.cache.folderMeasure?.[this.buObject.mid] || cache.getCache().folder
|
|
149
|
+
? Object.values(
|
|
150
|
+
this.cache.folderMeasure?.[this.buObject.mid] || cache.getCache().folder
|
|
151
|
+
)
|
|
152
|
+
.filter((item) => item.ContentType === 'measure')
|
|
153
|
+
.map((item) => item.ID)
|
|
154
|
+
: [];
|
|
155
|
+
if (fromCache.length) {
|
|
156
|
+
return fromCache;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const subTypeArr = ['measure'];
|
|
160
|
+
Util.logger.info(` - Caching dependent Metadata: folder`);
|
|
161
|
+
Util.logSubtypes(subTypeArr);
|
|
162
|
+
|
|
163
|
+
Folder.client = this.client;
|
|
164
|
+
Folder.buObject = this.buObject;
|
|
165
|
+
Folder.properties = this.properties;
|
|
166
|
+
this.cache.folderMeasure ||= {};
|
|
167
|
+
this.cache.folderMeasure[this.buObject.mid] = (
|
|
168
|
+
await Folder.retrieveForCache(null, subTypeArr)
|
|
169
|
+
).metadata;
|
|
170
|
+
return this._getMeasureFolderIds();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* helper for {@link DataFilter.retrieve}. uses cached dataExtensions to resolve dataExtensionFields
|
|
175
|
+
*
|
|
176
|
+
* @param {DataFilterMap} metadataTypeMap -
|
|
177
|
+
* @param {'retrieve'|'deploy'} [mode] -
|
|
178
|
+
*/
|
|
179
|
+
static async _cacheDeFields(metadataTypeMap, mode) {
|
|
180
|
+
const deKeys =
|
|
181
|
+
mode === 'retrieve'
|
|
182
|
+
? Object.values(metadataTypeMap)
|
|
183
|
+
.filter((item) => item.derivedFromObjectTypeName === 'DataExtension')
|
|
184
|
+
.filter((item) => item.derivedFromObjectId)
|
|
185
|
+
.map((item) => {
|
|
186
|
+
try {
|
|
187
|
+
const deKey = cache.searchForField(
|
|
188
|
+
'dataExtension',
|
|
189
|
+
item.derivedFromObjectId,
|
|
190
|
+
'ObjectID',
|
|
191
|
+
'CustomerKey'
|
|
192
|
+
);
|
|
193
|
+
if (deKey) {
|
|
194
|
+
this.deIdKeyMap ||= {};
|
|
195
|
+
this.deIdKeyMap[item.derivedFromObjectId] = deKey;
|
|
196
|
+
return deKey;
|
|
197
|
+
}
|
|
198
|
+
} catch {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
.filter(Boolean)
|
|
203
|
+
: Object.values(metadataTypeMap)
|
|
204
|
+
.filter((item) => item.r__source_dataExtension_key)
|
|
205
|
+
.map((item) => item.r__source_dataExtension_key)
|
|
206
|
+
.filter(
|
|
207
|
+
(deKey) =>
|
|
208
|
+
!this.cache.dataExtensionField ||
|
|
209
|
+
!this.cache.dataExtensionField[deKey]
|
|
210
|
+
)
|
|
211
|
+
.filter(Boolean);
|
|
212
|
+
if (deKeys.length) {
|
|
213
|
+
const deKeysUnique = [...new Set(deKeys)];
|
|
214
|
+
Util.logger.info(' - Caching dependent Metadata: dataExtensionField');
|
|
215
|
+
// only proceed with the download if we have dataExtension keys
|
|
216
|
+
const fieldOptions = {};
|
|
217
|
+
for (const deKey of deKeysUnique) {
|
|
218
|
+
fieldOptions.filter = fieldOptions.filter
|
|
219
|
+
? {
|
|
220
|
+
leftOperand: {
|
|
221
|
+
leftOperand: 'DataExtension.CustomerKey',
|
|
222
|
+
operator: 'equals',
|
|
223
|
+
rightOperand: deKey,
|
|
224
|
+
},
|
|
225
|
+
operator: 'OR',
|
|
226
|
+
rightOperand: fieldOptions.filter,
|
|
227
|
+
}
|
|
228
|
+
: {
|
|
229
|
+
leftOperand: 'DataExtension.CustomerKey',
|
|
230
|
+
operator: 'equals',
|
|
231
|
+
rightOperand: deKey,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
DataExtensionField.buObject = this.buObject;
|
|
235
|
+
DataExtensionField.client = this.client;
|
|
236
|
+
DataExtensionField.properties = this.properties;
|
|
237
|
+
this.saveDataExtensionFieldCacheToMap(
|
|
238
|
+
(await DataExtensionField.retrieveForCacheDE(fieldOptions, ['Name', 'ObjectID']))
|
|
239
|
+
.metadata
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* helper for {@link DataFilter._cacheDeFields}
|
|
245
|
+
*
|
|
246
|
+
* @param {DataExtensionFieldMap} deFieldCache -
|
|
247
|
+
*/
|
|
248
|
+
static saveDataExtensionFieldCacheToMap(deFieldCache) {
|
|
249
|
+
this.cache.dataExtensionField ||= {};
|
|
250
|
+
|
|
251
|
+
if (!deFieldCache) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
for (const field of Object.values(deFieldCache)) {
|
|
255
|
+
if (!field?.DataExtension?.CustomerKey) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (!this.cache.dataExtensionField[field.DataExtension.CustomerKey]) {
|
|
259
|
+
/** @type {Object.<string, DataExtensionFieldItem[]>} */
|
|
260
|
+
this.cache.dataExtensionField[field.DataExtension.CustomerKey] = [];
|
|
261
|
+
}
|
|
262
|
+
this.cache.dataExtensionField[field.DataExtension.CustomerKey].push(field);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* helper for {@link DataFilter.retrieve}
|
|
267
|
+
*
|
|
268
|
+
* @param {DataFilterMap} metadataTypeMap -
|
|
269
|
+
*/
|
|
270
|
+
static async _cacheContactAttributes(metadataTypeMap) {
|
|
271
|
+
if (this.cache.contactAttributes?.[this.buObject.mid]) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const subscriberFilters = Object.values(metadataTypeMap)
|
|
275
|
+
.filter((item) => item.derivedFromObjectTypeName === 'SubscriberAttributes')
|
|
276
|
+
.filter((item) => item.derivedFromObjectId);
|
|
277
|
+
if (subscriberFilters.length) {
|
|
278
|
+
Util.logger.info(' - Caching dependent Metadata: contactAttributes');
|
|
279
|
+
const response = await this.client.rest.get('/email/v1/Contacts/Attributes/');
|
|
280
|
+
const keyFieldBackup = this.definition.keyField;
|
|
281
|
+
this.definition.keyField = 'id';
|
|
282
|
+
this.cache.contactAttributes ||= {};
|
|
283
|
+
this.cache.contactAttributes[this.buObject.mid] = this.parseResponseBody(response);
|
|
284
|
+
this.definition.keyField = keyFieldBackup;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* helper for {@link DataFilter.retrieve}
|
|
289
|
+
*
|
|
290
|
+
* @param {DataFilterMap} metadataTypeMap -
|
|
291
|
+
*/
|
|
292
|
+
static async _cacheMeasures(metadataTypeMap) {
|
|
293
|
+
if (this.cache.measures?.[this.buObject.mid]) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const subscriberFilters = Object.values(metadataTypeMap)
|
|
297
|
+
.filter((item) => item.derivedFromObjectTypeName === 'SubscriberAttributes')
|
|
298
|
+
.filter((item) => item.derivedFromObjectId);
|
|
299
|
+
const measureFolders = await this._getMeasureFolderIds();
|
|
300
|
+
if (subscriberFilters.length) {
|
|
301
|
+
Util.logger.info(' - Caching dependent Metadata: measure');
|
|
302
|
+
const response = { items: [] };
|
|
303
|
+
for (const folderId of measureFolders) {
|
|
304
|
+
const metadataMapFolder = await this.client.rest.getBulk(
|
|
305
|
+
'email/v1/Measures/category/' + folderId + '/',
|
|
306
|
+
250 // 250 is what the GUI is using
|
|
307
|
+
);
|
|
308
|
+
if (Object.keys(metadataMapFolder.items).length) {
|
|
309
|
+
response.items.push(...metadataMapFolder.items);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const keyFieldBackup = this.definition.keyField;
|
|
314
|
+
this.definition.keyField = 'measureID';
|
|
315
|
+
this.cache.measures ||= {};
|
|
316
|
+
this.cache.measures[this.buObject.mid] = this.parseResponseBody(response);
|
|
317
|
+
this.definition.keyField = keyFieldBackup;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Retrieves all records for caching
|
|
323
|
+
*
|
|
324
|
+
* @returns {Promise.<{metadata: DataFilterMap, type: string}>} Promise of items
|
|
325
|
+
*/
|
|
326
|
+
static async retrieveForCache() {
|
|
327
|
+
return this.retrieve(null);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* parses retrieved Metadata before saving
|
|
332
|
+
*
|
|
333
|
+
* @param {DataFilterItem} metadata a single record
|
|
334
|
+
* @returns {Promise.<DataFilterItem>} parsed metadata definition
|
|
335
|
+
*/
|
|
336
|
+
static async postRetrieveTasks(metadata) {
|
|
337
|
+
// if (metadata.derivedFromType > 4) {
|
|
338
|
+
// // GUI only shows types 1,2,3,4; lets mimic that here.
|
|
339
|
+
// // type 6 seems to be journey related. Maybe we need to change that again in the future
|
|
340
|
+
// return;
|
|
341
|
+
// }
|
|
342
|
+
// folder
|
|
343
|
+
super.setFolderPath(metadata);
|
|
344
|
+
|
|
345
|
+
// parse XML filter for further processing in JSON format
|
|
346
|
+
const xmlToJson = new XMLParser({
|
|
347
|
+
preserveOrder: false, // XML parser returns undefined if this is true
|
|
348
|
+
ignoreAttributes: false,
|
|
349
|
+
allowBooleanAttributes: true,
|
|
350
|
+
});
|
|
351
|
+
metadata.c__filterDefinition = xmlToJson.parse(
|
|
352
|
+
metadata.filterDefinitionXml
|
|
353
|
+
)?.FilterDefinition;
|
|
354
|
+
delete metadata.filterDefinitionXml;
|
|
355
|
+
switch (metadata.derivedFromType) {
|
|
356
|
+
case 1: {
|
|
357
|
+
// if (metadata.c__filterDefinition['@_Source'] === 'SubscriberAttribute') {
|
|
358
|
+
// if (
|
|
359
|
+
// metadata.derivedFromObjectId &&
|
|
360
|
+
// metadata.derivedFromObjectId !== '00000000-0000-0000-0000-000000000000'
|
|
361
|
+
// ) {
|
|
362
|
+
// // Lists
|
|
363
|
+
// try {
|
|
364
|
+
// metadata.r__source_list_PathName = cache.getListPathName(
|
|
365
|
+
// metadata.derivedFromObjectId,
|
|
366
|
+
// 'ObjectID'
|
|
367
|
+
// );
|
|
368
|
+
// } catch {
|
|
369
|
+
// Util.logger.warn(
|
|
370
|
+
// ` - skipping ${this.definition.type} ${metadata.key}: list ${metadata.derivedFromObjectId} not found on current or Parent BU`
|
|
371
|
+
// );
|
|
372
|
+
// }
|
|
373
|
+
// } else {
|
|
374
|
+
// // SubscriberAttributes
|
|
375
|
+
// // - nothing to do
|
|
376
|
+
// }
|
|
377
|
+
// }
|
|
378
|
+
// // SubscriberAttributes
|
|
379
|
+
// this._postRetrieve_resolveAttributeIds(metadata);
|
|
380
|
+
// delete metadata.derivedFromObjectId;
|
|
381
|
+
// delete metadata.derivedFromObjectName;
|
|
382
|
+
// delete metadata.derivedFromObjectTypeName;
|
|
383
|
+
// delete metadata.derivedFromType;
|
|
384
|
+
// delete metadata.c__filterDefinition['@_Source'];
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
case 2: {
|
|
388
|
+
// DataExtension + XXX?
|
|
389
|
+
if (
|
|
390
|
+
metadata.c__filterDefinition['@_Source'] === 'Meta' ||
|
|
391
|
+
metadata.derivedFromObjectId === '00000000-0000-0000-0000-000000000000'
|
|
392
|
+
) {
|
|
393
|
+
// TODO - weird so far not understood case of Source=Meta
|
|
394
|
+
// sample: <FilterDefinition Source=\"Meta\"><Include><ConditionSet Operator=\"OR\" ConditionSetName=\"Individual Filter Grouping\"><Condition ID=\"55530cec-1df4-e611-80cc-1402ec7222b4\" isParam=\"false\" isPathed=\"true\" pathAttrGroupID=\"75530cec-1df4-e611-80cc-1402ec7222b4\" Operator=\"Equal\"><Value><![CDATA[994607]]></Value></Condition><Condition ID=\"55530cec-1df4-e611-80cc-1402ec7222b4\" isParam=\"false\" isPathed=\"true\" pathAttrGroupID=\"75530cec-1df4-e611-80cc-1402ec7222b4\" Operator=\"Equal\"><Value><![CDATA[3624804]]></Value></Condition></ConditionSet></Include><Exclude></Exclude></FilterDefinition>
|
|
395
|
+
} else if (metadata.c__filterDefinition['@_Source'] === 'DataExtension') {
|
|
396
|
+
// DataExtension
|
|
397
|
+
try {
|
|
398
|
+
metadata.r__source_dataExtension_key =
|
|
399
|
+
this.deIdKeyMap?.[metadata.derivedFromObjectId] ||
|
|
400
|
+
cache.searchForField(
|
|
401
|
+
'dataExtension',
|
|
402
|
+
metadata.derivedFromObjectId,
|
|
403
|
+
'ObjectID',
|
|
404
|
+
'CustomerKey'
|
|
405
|
+
);
|
|
406
|
+
delete metadata.derivedFromObjectName;
|
|
407
|
+
delete metadata.derivedFromObjectTypeName;
|
|
408
|
+
} catch {
|
|
409
|
+
Util.logger.debug(
|
|
410
|
+
` - skipping ${this.definition.type} ${metadata.key}: dataExtension ${metadata.derivedFromObjectId} not found on BU`
|
|
411
|
+
);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
this._resolveFields(metadata, 'postRetrieve');
|
|
415
|
+
|
|
416
|
+
delete metadata.derivedFromObjectId;
|
|
417
|
+
delete metadata.derivedFromType;
|
|
418
|
+
delete metadata.c__filterDefinition['@_Source'];
|
|
419
|
+
delete metadata.c__filterDefinition['@_SourceID'];
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return metadata;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* helper for {@link postRetrieveTasks}
|
|
430
|
+
*
|
|
431
|
+
* @param {DataFilterItem} metadata -
|
|
432
|
+
* @param {'postRetrieve'|'preDeploy'} mode -
|
|
433
|
+
* @param {DataExtensionFieldItem[]} [fieldCache] -
|
|
434
|
+
* @param {FilterConditionSet} [filter] -
|
|
435
|
+
* @returns {void}
|
|
436
|
+
*/
|
|
437
|
+
static _resolveFields(metadata, mode, fieldCache, filter) {
|
|
438
|
+
if (!filter) {
|
|
439
|
+
return this._resolveFields(
|
|
440
|
+
metadata,
|
|
441
|
+
mode,
|
|
442
|
+
this.cache.dataExtensionField[metadata.r__source_dataExtension_key],
|
|
443
|
+
metadata.c__filterDefinition?.ConditionSet
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
if (filter.Condition) {
|
|
447
|
+
const conditionsArr = Array.isArray(filter.Condition)
|
|
448
|
+
? filter.Condition
|
|
449
|
+
: [filter.Condition];
|
|
450
|
+
if (mode === 'postRetrieve') {
|
|
451
|
+
for (const condition of conditionsArr) {
|
|
452
|
+
this._postRetrieve_resolveFieldIdsCondition(metadata, condition, fieldCache);
|
|
453
|
+
}
|
|
454
|
+
} else if (mode === 'preDeploy') {
|
|
455
|
+
for (const condition of conditionsArr) {
|
|
456
|
+
this._preDeploy_resolveFieldNamesCondition(metadata, condition, fieldCache);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if (filter.ConditionSet) {
|
|
461
|
+
const conditionSet = Array.isArray(filter.ConditionSet)
|
|
462
|
+
? filter.ConditionSet
|
|
463
|
+
: [filter.ConditionSet];
|
|
464
|
+
for (const cs of conditionSet) {
|
|
465
|
+
this._resolveFields(metadata, mode, fieldCache, cs);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* helper for {@link _resolveFields}
|
|
471
|
+
*
|
|
472
|
+
* @param {DataFilterItem} metadata -
|
|
473
|
+
* @param {FilterCondition} condition -
|
|
474
|
+
* @param {DataExtensionFieldItem[]} fieldCache -
|
|
475
|
+
* @returns {void}
|
|
476
|
+
*/
|
|
477
|
+
static _postRetrieve_resolveFieldIdsCondition(metadata, condition, fieldCache) {
|
|
478
|
+
condition.r__dataExtensionField_name = fieldCache.find(
|
|
479
|
+
(field) => field.ObjectID === condition['@_ID']
|
|
480
|
+
)?.Name;
|
|
481
|
+
if (condition.r__dataExtensionField_name) {
|
|
482
|
+
delete condition['@_ID'];
|
|
483
|
+
} else {
|
|
484
|
+
Util.logger.warn(
|
|
485
|
+
` - ${this.definition.type} ${metadata[this.definition.keyField]}: could not resolve dataExtensionField with ID ${condition['@_ID']} in condition`
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
if (['IsEmpty', 'IsNotEmpty'].includes(condition['@_Operator'])) {
|
|
489
|
+
delete condition.Value;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* helper for {@link _resolveFields}
|
|
494
|
+
*
|
|
495
|
+
* @param {DataFilterItem} metadata -
|
|
496
|
+
* @param {FilterCondition} condition -
|
|
497
|
+
* @param {DataExtensionFieldItem[]} fieldCache -
|
|
498
|
+
* @returns {void}
|
|
499
|
+
*/
|
|
500
|
+
static _preDeploy_resolveFieldNamesCondition(metadata, condition, fieldCache) {
|
|
501
|
+
condition['@_ID'] = fieldCache.find(
|
|
502
|
+
(field) => field.Name === condition.r__dataExtensionField_name
|
|
503
|
+
)?.ObjectID;
|
|
504
|
+
if (condition['@_ID']) {
|
|
505
|
+
delete condition.r__dataExtensionField_name;
|
|
506
|
+
} else {
|
|
507
|
+
throw new Error(
|
|
508
|
+
` - ${this.definition.type} ${metadata[this.definition.keyField]}: could not resolve dataExtensionField with Name ${condition.r__dataExtensionField_name} in condition`
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
if (['IsEmpty', 'IsNotEmpty'].includes(condition['@_Operator'])) {
|
|
512
|
+
condition.Value ||= '';
|
|
513
|
+
} else if (condition?.Value && typeof condition.Value !== 'object') {
|
|
514
|
+
// allow adding cdata
|
|
515
|
+
// @ts-ignore
|
|
516
|
+
condition.Value = { cdata: condition.Value };
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* helper for {@link postRetrieveTasks}
|
|
521
|
+
*
|
|
522
|
+
* @param {DataFilterItem} metadata -
|
|
523
|
+
* @param {object} [filter] -
|
|
524
|
+
* @returns {void}
|
|
525
|
+
*/
|
|
526
|
+
static _postRetrieve_resolveAttributeIds(metadata, filter) {
|
|
527
|
+
if (!filter) {
|
|
528
|
+
return this._postRetrieve_resolveAttributeIds(
|
|
529
|
+
metadata,
|
|
530
|
+
metadata.c__filterDefinition?.ConditionSet
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
const contactAttributes = this.cache.contactAttributes[this.buObject.mid];
|
|
534
|
+
const measures = this.cache.measures[this.buObject.mid];
|
|
535
|
+
const conditionsArr = Array.isArray(filter.Condition)
|
|
536
|
+
? filter.Condition
|
|
537
|
+
: [filter.Condition];
|
|
538
|
+
for (const condition of conditionsArr) {
|
|
539
|
+
condition['@_ID'] += '';
|
|
540
|
+
if (condition['@_SourceType'] === 'Measure' && measures[condition['@_ID']]) {
|
|
541
|
+
condition.r__measure = measures[condition['@_ID']]?.name;
|
|
542
|
+
delete condition['@_ID'];
|
|
543
|
+
} else if (
|
|
544
|
+
condition['@_SourceType'] !== 'Measure' &&
|
|
545
|
+
contactAttributes[condition['@_ID']]
|
|
546
|
+
) {
|
|
547
|
+
condition.r__contactAttribute = contactAttributes[condition['@_ID']]?.name;
|
|
548
|
+
delete condition['@_ID'];
|
|
549
|
+
}
|
|
550
|
+
if (['IsEmpty', 'IsNotEmpty'].includes(condition['@_Operator'])) {
|
|
551
|
+
delete condition.Value;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (filter.ConditionSet) {
|
|
555
|
+
this._postRetrieve_resolveAttributeIds(metadata, filter.ConditionSet);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* prepares a item for deployment
|
|
561
|
+
*
|
|
562
|
+
* @param {DataFilterItem} metadata a single record
|
|
563
|
+
* @returns {Promise.<DataFilterItem>} Promise of updated single item
|
|
564
|
+
*/
|
|
565
|
+
static async preDeployTasks(metadata) {
|
|
566
|
+
// folder
|
|
567
|
+
super.setFolderId(metadata);
|
|
568
|
+
|
|
569
|
+
// disable updates to r__source_dataExtension_key
|
|
570
|
+
// the API and GUI prevent changes to the source data extensions.
|
|
571
|
+
// to avoid confusion and accidental changes, we will reset the values from cache before deployment
|
|
572
|
+
const normalizedKey = File.reverseFilterIllegalFilenames(
|
|
573
|
+
metadata[this.definition.keyField]
|
|
574
|
+
);
|
|
575
|
+
const cachedVersion = cache.getByKey(this.definition.type, normalizedKey);
|
|
576
|
+
|
|
577
|
+
// DataExtension
|
|
578
|
+
if (metadata.r__source_dataExtension_key) {
|
|
579
|
+
metadata.derivedFromObjectId = cache.searchForField(
|
|
580
|
+
'dataExtension',
|
|
581
|
+
metadata.r__source_dataExtension_key,
|
|
582
|
+
'CustomerKey',
|
|
583
|
+
'ObjectID'
|
|
584
|
+
);
|
|
585
|
+
if (
|
|
586
|
+
cachedVersion &&
|
|
587
|
+
cachedVersion.derivedFromObjectId !== metadata.derivedFromObjectId
|
|
588
|
+
) {
|
|
589
|
+
throw new Error(
|
|
590
|
+
`Updating r__source_dataExtension_key is not allowed. You need to delete and re-create the dataFilter to change this.`
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
metadata.derivedFromObjectName = cache.searchForField(
|
|
594
|
+
'dataExtension',
|
|
595
|
+
metadata.r__source_dataExtension_key,
|
|
596
|
+
'CustomerKey',
|
|
597
|
+
'Name'
|
|
598
|
+
);
|
|
599
|
+
metadata.derivedFromObjectTypeName = 'DataExtension';
|
|
600
|
+
metadata.derivedFromType = 2;
|
|
601
|
+
metadata.c__filterDefinition['@_Source'] = 'DataExtension';
|
|
602
|
+
metadata.c__filterDefinition['@_SourceID'] = metadata.derivedFromObjectId;
|
|
603
|
+
this._resolveFields(metadata, 'preDeploy');
|
|
604
|
+
|
|
605
|
+
delete metadata.r__source_dataExtension_key;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const jsonToXml = new XMLBuilder({
|
|
609
|
+
preserveOrder: false, // XML Builder returns undefined if this is true
|
|
610
|
+
ignoreAttributes: false,
|
|
611
|
+
cdataPropName: 'cdata',
|
|
612
|
+
});
|
|
613
|
+
metadata.filterDefinitionXml = jsonToXml.build({
|
|
614
|
+
FilterDefinition: metadata.c__filterDefinition,
|
|
615
|
+
});
|
|
616
|
+
delete metadata.c__filterDefinition;
|
|
617
|
+
return metadata;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* MetadataType upsert, after retrieving from target and comparing to check if create or update operation is needed.
|
|
622
|
+
*
|
|
623
|
+
* @param {MetadataTypeMap} metadataMap metadata mapped by their keyField
|
|
624
|
+
* @param {string} deployDir directory where deploy metadata are saved
|
|
625
|
+
* @param {boolean} [runUpsertSequentially] when a type has self-dependencies creates need to run one at a time and created/changed keys need to be cached to ensure following creates/updates have thoses keys available
|
|
626
|
+
* @returns {Promise.<MetadataTypeMap>} keyField => metadata map
|
|
627
|
+
*/
|
|
628
|
+
static async upsert(metadataMap, deployDir, runUpsertSequentially = false) {
|
|
629
|
+
Util.logBeta(this.definition.type);
|
|
630
|
+
await this._cacheDeFields(metadataMap, 'deploy');
|
|
631
|
+
return super.upsert(metadataMap, deployDir, runUpsertSequentially);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Creates a single item
|
|
635
|
+
*
|
|
636
|
+
* @param {DataFilterItem} metadata a single item
|
|
637
|
+
* @returns {Promise.<DataFilterItem>} Promise
|
|
638
|
+
*/
|
|
639
|
+
static create(metadata) {
|
|
640
|
+
return super.createREST(metadata, '/email/v1/filters/filterdefinition/');
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Updates a single item
|
|
644
|
+
*
|
|
645
|
+
* @param {DataFilterItem} metadata a single item
|
|
646
|
+
* @returns {Promise.<DataFilterItem>} Promise
|
|
647
|
+
*/
|
|
648
|
+
static update(metadata) {
|
|
649
|
+
return super.updateREST(
|
|
650
|
+
metadata,
|
|
651
|
+
'/email/v1/filters/filterdefinition/' + metadata[this.definition.idField]
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* helper to allow us to select single metadata entries via REST
|
|
657
|
+
*
|
|
658
|
+
* @private
|
|
659
|
+
* @param {string} key customer key
|
|
660
|
+
* @returns {Promise.<string>} objectId or empty string
|
|
661
|
+
*/
|
|
662
|
+
static async _getObjectIdForSingleRetrieve(key) {
|
|
663
|
+
const name = key.startsWith('name:') ? key.slice(5) : null;
|
|
664
|
+
const response = await this.client.soap.retrieve(this.definition.soapType, ['ObjectID'], {
|
|
665
|
+
filter: {
|
|
666
|
+
leftOperand: name ? 'Name' : 'CustomerKey',
|
|
667
|
+
operator: 'equals',
|
|
668
|
+
rightOperand: name || key,
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
return response?.Results?.length ? response.Results[0].ObjectID : null;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Delete a metadata item from the specified business unit
|
|
676
|
+
*
|
|
677
|
+
* @param {string} key Identifier of data extension
|
|
678
|
+
* @returns {Promise.<boolean>} deletion success flag
|
|
679
|
+
*/
|
|
680
|
+
static async deleteByKey(key) {
|
|
681
|
+
// delete only works with the query's object id
|
|
682
|
+
const objectId = key ? await this._getObjectIdForSingleRetrieve(key) : null;
|
|
683
|
+
if (!objectId) {
|
|
684
|
+
await this.deleteNotFound(key);
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
return super.deleteByKeyREST('/email/v1/filters/filterdefinition/' + objectId, key);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
// Assign definition to static attributes
|
|
691
|
+
import MetadataTypeDefinitions from '../MetadataTypeDefinitions.js';
|
|
692
|
+
DataFilter.definition = MetadataTypeDefinitions.dataFilter;
|
|
693
|
+
|
|
694
|
+
export default DataFilter;
|