diff --git a/src/warehouse/index.js b/src/warehouse/index.js index 0750f7dbc1..773b87199a 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -563,7 +563,6 @@ function processWarehouseMessage(message, options) { message.integrations && message.integrations[options.provider.toUpperCase()] ? message.integrations[options.provider.toUpperCase()].options : {}; - const responses = []; const eventType = message.type?.toLowerCase(); const skipTracksTable = @@ -585,13 +584,6 @@ function processWarehouseMessage(message, options) { // For older destinations, it will come as true, and for new destinations this config will not be present, which means we will treat it as false. const allowUsersContextTraits = options.destConfig?.allowUsersContextTraits || false; - // allowEventContextTraits when set to true, if context.traits.* is present, it will be added as context_traits_* in the events table, - // e.g., for context.traits.name, context_traits_name will be added to the events table. - // allowEventContextTraits when set to false, if context.traits.* is present, nothing will be added in the events table. - // e.g., for context.traits.name, nothing will be added to the events table. - // For older destinations, it will come as true, and for new destinations this config will not be present, which means we will treat it as false. - const allowEventContextTraits = options.destConfig?.allowEventContextTraits || false; - addJsonKeysToOptions(options); if (isBlank(message.messageId)) { @@ -805,14 +797,6 @@ function processWarehouseMessage(message, options) { ...trackProps, ...commonProps, }; - if (!allowEventContextTraits) { - // remove all context traits from eventTableEvent - Object.keys(eventTableEvent).forEach((key) => { - if (key.toLowerCase().startsWith('context_traits_')) { - delete eventTableEvent[key]; - } - }); - } const eventTableMetadata = { table: excludeRudderCreatedTableNames( utils.safeTableName( diff --git a/src/warehouse/snakecase/snakecase.js b/src/warehouse/snakecase/snakecase.js new file mode 100644 index 0000000000..7dca78dcf5 --- /dev/null +++ b/src/warehouse/snakecase/snakecase.js @@ -0,0 +1,37 @@ +import { toString } from 'lodash'; +import { unicodeWords, unicodeWordsWithNumbers } from './unicodeWords'; + +const hasUnicodeWord = RegExp.prototype.test.bind( + /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/, +); + +/** Used to match words composed of alphanumeric characters. */ +// eslint-disable-next-line no-control-regex +const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + +function asciiWords(string) { + return string.match(reAsciiWord); +} + +function words(string) { + const result = hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string); + return result || []; +} + +function wordsWithNumbers(string) { + const result = hasUnicodeWord(string) ? unicodeWordsWithNumbers(string) : asciiWords(string); + return result || []; +} + +const snakeCase = (string) => + words(toString(string).replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? '_' : '') + word.toLowerCase(), + '', + ); +const snakeCaseWithNumbers = (string) => + wordsWithNumbers(toString(string).replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? '_' : '') + word.toLowerCase(), + '', + ); + +export { words, wordsWithNumbers, snakeCase, snakeCaseWithNumbers }; diff --git a/src/warehouse/snakecase/unicodeWords.js b/src/warehouse/snakecase/unicodeWords.js new file mode 100644 index 0000000000..ecbfbe1243 --- /dev/null +++ b/src/warehouse/snakecase/unicodeWords.js @@ -0,0 +1,94 @@ +/** Used to compose unicode character classes. */ +const rsAstralRange = '\\ud800-\\udfff'; +const rsComboMarksRange = '\\u0300-\\u036f'; +const reComboHalfMarksRange = '\\ufe20-\\ufe2f'; +const rsComboSymbolsRange = '\\u20d0-\\u20ff'; +const rsComboMarksExtendedRange = '\\u1ab0-\\u1aff'; +const rsComboMarksSupplementRange = '\\u1dc0-\\u1dff'; +const rsComboRange = + rsComboMarksRange + + reComboHalfMarksRange + + rsComboSymbolsRange + + rsComboMarksExtendedRange + + rsComboMarksSupplementRange; +const rsDingbatRange = '\\u2700-\\u27bf'; +const rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff'; +const rsMathOpRange = '\\xac\\xb1\\xd7\\xf7'; +const rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf'; +const rsPunctuationRange = '\\u2000-\\u206f'; +const rsSpaceRange = + ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000'; +const rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde'; +const rsVarRange = '\\ufe0e\\ufe0f'; +const rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + +/** Used to compose unicode capture groups. */ +const rsApos = "['\u2019]"; +const rsBreak = `[${rsBreakRange}]`; +const rsCombo = `[${rsComboRange}]`; +const rsDigit = '\\d'; +const rsDingbat = `[${rsDingbatRange}]`; +const rsLower = `[${rsLowerRange}]`; +const rsMisc = `[^${rsAstralRange}${rsBreakRange + rsDigit + rsDingbatRange + rsLowerRange + rsUpperRange}]`; +const rsFitz = '\\ud83c[\\udffb-\\udfff]'; +const rsModifier = `(?:${rsCombo}|${rsFitz})`; +const rsNonAstral = `[^${rsAstralRange}]`; +const rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}'; +const rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]'; +const rsUpper = `[${rsUpperRange}]`; +const rsZWJ = '\\u200d'; + +/** Used to compose unicode regexes. */ +const rsMiscLower = `(?:${rsLower}|${rsMisc})`; +const rsMiscUpper = `(?:${rsUpper}|${rsMisc})`; +const rsOptContrLower = `(?:${rsApos}(?:d|ll|m|re|s|t|ve))?`; +const rsOptContrUpper = `(?:${rsApos}(?:D|LL|M|RE|S|T|VE))?`; +const reOptMod = `${rsModifier}?`; +const rsOptVar = `[${rsVarRange}]?`; +const rsOptJoin = `(?:${rsZWJ}(?:${[rsNonAstral, rsRegional, rsSurrPair].join('|')})${rsOptVar + reOptMod})*`; +const rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])'; +const rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])'; +const rsSeq = rsOptVar + reOptMod + rsOptJoin; +const rsEmoji = `(?:${[rsDingbat, rsRegional, rsSurrPair].join('|')})${rsSeq}`; + +const reUnicodeWords = RegExp( + [ + `${rsUpper}?${rsLower}+${rsOptContrLower}(?=${[rsBreak, rsUpper, '$'].join('|')})`, // Regular words, lowercase letters followed by optional contractions + `${rsMiscUpper}+${rsOptContrUpper}(?=${[rsBreak, rsUpper + rsMiscLower, '$'].join('|')})`, // Miscellaneous uppercase characters with optional contractions + `${rsUpper}?${rsMiscLower}+${rsOptContrLower}`, // Miscellaneous lowercase sequences with optional contractions + `${rsUpper}+${rsOptContrUpper}`, // All uppercase words with optional contractions (e.g., "THIS") + rsOrdUpper, // Ordinals for uppercase (e.g., "1ST", "2ND") + rsOrdLower, // Ordinals for lowercase (e.g., "1st", "2nd") + `${rsDigit}+`, // Pure digits (e.g., "123") + rsEmoji, // Emojis (e.g., 😀, ❤️) + ].join('|'), + 'g', +); + +const reUnicodeWordsWithNumbers = RegExp( + [ + `${rsUpper}?${rsLower}+${rsDigit}+`, // Lowercase letters followed by digits (e.g., "abc123") + `${rsUpper}+${rsDigit}+`, // Uppercase letters followed by digits (e.g., "ABC123") + `${rsDigit}+${rsUpper}?${rsLower}+`, // Digits followed by lowercase letters (e.g., "123abc") + `${rsDigit}+${rsUpper}+`, // Digits followed by uppercase letters (e.g., "123ABC") + `${rsUpper}?${rsLower}+${rsOptContrLower}(?=${[rsBreak, rsUpper, '$'].join('|')})`, // Regular words, lowercase letters followed by optional contractions + `${rsMiscUpper}+${rsOptContrUpper}(?=${[rsBreak, rsUpper + rsMiscLower, '$'].join('|')})`, // Miscellaneous uppercase characters with optional contractions + `${rsUpper}?${rsMiscLower}+${rsOptContrLower}`, // Miscellaneous lowercase sequences with optional contractions + `${rsUpper}+${rsOptContrUpper}`, // All uppercase words with optional contractions (e.g., "THIS") + rsOrdUpper, // Ordinals for uppercase (e.g., "1ST", "2ND") + rsOrdLower, // Ordinals for lowercase (e.g., "1st", "2nd") + `${rsDigit}+`, // Pure digits (e.g., "123") + rsEmoji, // Emojis (e.g., 😀, ❤️) + ].join('|'), + 'g', +); + +function unicodeWords(string) { + return string.match(reUnicodeWords); +} + +function unicodeWordsWithNumbers(string) { + return string.match(reUnicodeWordsWithNumbers); +} + +export { unicodeWords, unicodeWordsWithNumbers }; diff --git a/src/warehouse/util.js b/src/warehouse/util.js index a2c6271d64..7f4e224a34 100644 --- a/src/warehouse/util.js +++ b/src/warehouse/util.js @@ -1,4 +1,3 @@ -const _ = require('lodash'); const get = require('get-value'); const v1 = require('./v1/util'); diff --git a/src/warehouse/v1/util.js b/src/warehouse/v1/util.js index 43cb1d856d..d1289bc674 100644 --- a/src/warehouse/v1/util.js +++ b/src/warehouse/v1/util.js @@ -1,8 +1,7 @@ -const _ = require('lodash'); - const reservedANSIKeywordsMap = require('../config/ReservedKeywords.json'); const { isDataLakeProvider } = require('../config/helpers'); const { TransformationError } = require('@rudderstack/integrations-lib'); +const { snakeCase, snakeCaseWithNumbers } = require('../snakecase/snakecase'); function safeTableName(options, name = '') { const { provider } = options; @@ -104,14 +103,17 @@ function transformName(options, provider, name = '') { if (extractedValue !== '') { extractedValues.push(extractedValue); } + const underscoreDivideNumbers = options?.underscoreDivideNumbers || false; + const snakeCaseFn = underscoreDivideNumbers ? snakeCase : snakeCaseWithNumbers; + let key = extractedValues.join('_'); if (name.startsWith('_')) { // do not remove leading underscores to allow esacaping rudder keywords with underscore // _timestamp -> _timestamp // __timestamp -> __timestamp - key = name.match(/^_*/)[0] + _.snakeCase(key.replace(/^_*/, '')); + key = name.match(/^_*/)[0] + snakeCaseFn(key.replace(/^_*/, '')); } else { - key = _.snakeCase(key); + key = snakeCaseFn(key); } if (key !== '' && key.charCodeAt(0) >= 48 && key.charCodeAt(0) <= 57) { @@ -120,9 +122,6 @@ function transformName(options, provider, name = '') { if (provider === 'postgres') { key = key.substr(0, 63); } - if (!options?.underscoreDivideNumbers) { - key = key.replace(/(\w)_(\d+)/g, '$1$2'); - } return key; } diff --git a/test/__tests__/data/warehouse/events.js b/test/__tests__/data/warehouse/events.js index 1b47ec1790..bca6f776be 100644 --- a/test/__tests__/data/warehouse/events.js +++ b/test/__tests__/data/warehouse/events.js @@ -10,7 +10,6 @@ const sampleEvents = { prefixProperties: true, useNativeSDK: false, allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true }, DestinationDefinition: { @@ -519,7 +518,6 @@ const sampleEvents = { prefixProperties: true, useNativeSDK: false, allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true }, DestinationDefinition: { @@ -1034,7 +1032,6 @@ const sampleEvents = { prefixProperties: true, useNativeSDK: false, allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true }, DestinationDefinition: { @@ -1294,7 +1291,6 @@ const sampleEvents = { trackCategorisedPages: true, trackNamedPages: false, allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true }, Enabled: true @@ -1546,7 +1542,6 @@ const sampleEvents = { trackCategorisedPages: false, trackNamedPages: false, allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true }, Enabled: true @@ -1769,7 +1764,6 @@ const sampleEvents = { prefixProperties: true, useNativeSDK: false, allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true }, DestinationDefinition: { @@ -2036,7 +2030,6 @@ const sampleEvents = { prefixProperties: true, useNativeSDK: false, allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true }, DestinationDefinition: { diff --git a/test/__tests__/data/warehouse/integration_options_events.js b/test/__tests__/data/warehouse/integration_options_events.js index 0e1ea10af8..bb068d4857 100644 --- a/test/__tests__/data/warehouse/integration_options_events.js +++ b/test/__tests__/data/warehouse/integration_options_events.js @@ -22,7 +22,6 @@ const sampleEvents = { Config: { jsonPaths: " testMap.nestedMap, testArray", allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, @@ -736,7 +735,6 @@ const sampleEvents = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js index 93aea31dd9..30cce51fb7 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js index ddedd87282..9d38ecc292 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js index 219b625707..bbae993b27 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js index 6abe5b71bd..14b01d4cda 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js index dd81123757..dc2d3a3318 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js index 6bf44e5ba5..9b789d2747 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js index f117894e77..691ce57ca1 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js index 8145d6a3bb..d5d57f85b9 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js index eb27b44a1f..a950b7f526 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js index 7eb3aba247..6979aa1100 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js index 548ede9614..884770864a 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js index 81008448dc..d5282c1cfd 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js index 398e013070..3eec47b89d 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js index 04005ff434..6b411835db 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js @@ -3,7 +3,6 @@ module.exports = { destination: { Config: { allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true } }, diff --git a/test/__tests__/snakecase.test.js b/test/__tests__/snakecase.test.js new file mode 100644 index 0000000000..9112f5d79b --- /dev/null +++ b/test/__tests__/snakecase.test.js @@ -0,0 +1,498 @@ +import lodashStable from 'lodash'; + +const {words, wordsWithNumbers, snakeCase, snakeCaseWithNumbers} = require("../../src/warehouse/snakecase/snakecase"); + +const burredLetters = [ + // Latin-1 Supplement letters. + '\xc0', + '\xc1', + '\xc2', + '\xc3', + '\xc4', + '\xc5', + '\xc6', + '\xc7', + '\xc8', + '\xc9', + '\xca', + '\xcb', + '\xcc', + '\xcd', + '\xce', + '\xcf', + '\xd0', + '\xd1', + '\xd2', + '\xd3', + '\xd4', + '\xd5', + '\xd6', + '\xd8', + '\xd9', + '\xda', + '\xdb', + '\xdc', + '\xdd', + '\xde', + '\xdf', + '\xe0', + '\xe1', + '\xe2', + '\xe3', + '\xe4', + '\xe5', + '\xe6', + '\xe7', + '\xe8', + '\xe9', + '\xea', + '\xeb', + '\xec', + '\xed', + '\xee', + '\xef', + '\xf0', + '\xf1', + '\xf2', + '\xf3', + '\xf4', + '\xf5', + '\xf6', + '\xf8', + '\xf9', + '\xfa', + '\xfb', + '\xfc', + '\xfd', + '\xfe', + '\xff', + // Latin Extended-A letters. + '\u0100', + '\u0101', + '\u0102', + '\u0103', + '\u0104', + '\u0105', + '\u0106', + '\u0107', + '\u0108', + '\u0109', + '\u010a', + '\u010b', + '\u010c', + '\u010d', + '\u010e', + '\u010f', + '\u0110', + '\u0111', + '\u0112', + '\u0113', + '\u0114', + '\u0115', + '\u0116', + '\u0117', + '\u0118', + '\u0119', + '\u011a', + '\u011b', + '\u011c', + '\u011d', + '\u011e', + '\u011f', + '\u0120', + '\u0121', + '\u0122', + '\u0123', + '\u0124', + '\u0125', + '\u0126', + '\u0127', + '\u0128', + '\u0129', + '\u012a', + '\u012b', + '\u012c', + '\u012d', + '\u012e', + '\u012f', + '\u0130', + '\u0131', + '\u0132', + '\u0133', + '\u0134', + '\u0135', + '\u0136', + '\u0137', + '\u0138', + '\u0139', + '\u013a', + '\u013b', + '\u013c', + '\u013d', + '\u013e', + '\u013f', + '\u0140', + '\u0141', + '\u0142', + '\u0143', + '\u0144', + '\u0145', + '\u0146', + '\u0147', + '\u0148', + '\u0149', + '\u014a', + '\u014b', + '\u014c', + '\u014d', + '\u014e', + '\u014f', + '\u0150', + '\u0151', + '\u0152', + '\u0153', + '\u0154', + '\u0155', + '\u0156', + '\u0157', + '\u0158', + '\u0159', + '\u015a', + '\u015b', + '\u015c', + '\u015d', + '\u015e', + '\u015f', + '\u0160', + '\u0161', + '\u0162', + '\u0163', + '\u0164', + '\u0165', + '\u0166', + '\u0167', + '\u0168', + '\u0169', + '\u016a', + '\u016b', + '\u016c', + '\u016d', + '\u016e', + '\u016f', + '\u0170', + '\u0171', + '\u0172', + '\u0173', + '\u0174', + '\u0175', + '\u0176', + '\u0177', + '\u0178', + '\u0179', + '\u017a', + '\u017b', + '\u017c', + '\u017d', + '\u017e', + '\u017f', +]; +const emojiVar = '\ufe0f'; +const flag = '\ud83c\uddfa\ud83c\uddf8'; +const heart = `\u2764${emojiVar}`; +const hearts = '\ud83d\udc95'; +const comboGlyph = `\ud83d\udc68\u200d${heart}\u200d\ud83d\udc8B\u200d\ud83d\udc68`; +const leafs = '\ud83c\udf42'; +const rocket = '\ud83d\ude80'; +const stubTrue = function () { + return true; +}; +const stubString = function () { + return ''; +}; + +describe('words', () => { + it('should match words containing Latin Unicode letters', () => { + const expected = lodashStable.map(burredLetters, (letter) => [letter]); + const actual = lodashStable.map(burredLetters, (letter) => words(letter)); + expect(actual).toEqual(expected); + }); + + it('should work with compound words', () => { + expect(words('12ft')).toEqual(['12', 'ft']); + expect(words('aeiouAreVowels')).toEqual(['aeiou', 'Are', 'Vowels']); + expect(words('enable 6h format')).toEqual(['enable', '6', 'h', 'format']); + expect(words('enable 24H format')).toEqual(['enable', '24', 'H', 'format']); + expect(words('isISO8601')).toEqual(['is', 'ISO', '8601']); + expect(words('LETTERSAeiouAreVowels')).toEqual(['LETTERS', 'Aeiou', 'Are', 'Vowels']); + expect(words('tooLegit2Quit')).toEqual(['too', 'Legit', '2', 'Quit']); + expect(words('walk500Miles')).toEqual(['walk', '500', 'Miles']); + expect(words('xhr2Request')).toEqual(['xhr', '2', 'Request']); + expect(words('XMLHttp')).toEqual(['XML', 'Http']); + expect(words('XmlHTTP')).toEqual(['Xml', 'HTTP']); + expect(words('XmlHttp')).toEqual(['Xml', 'Http']); + }); + + it('should work with compound words containing diacritical marks', () => { + expect(words('LETTERSÆiouAreVowels')).toEqual(['LETTERS', 'Æiou', 'Are', 'Vowels']); + expect(words('æiouAreVowels')).toEqual(['æiou', 'Are', 'Vowels']); + expect(words('æiou2Consonants')).toEqual(['æiou', '2', 'Consonants']); + }); + + it('should not treat contractions as separate words', () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + lodashStable.each(["'", '\u2019'], (apos) => { + lodashStable.times(2, (index) => { + const actual = lodashStable.map(postfixes, (postfix) => { + const string = `a b${apos}${postfix} c`; + return words(string[index ? 'toUpperCase' : 'toLowerCase']()); + }); + const expected = lodashStable.map(postfixes, (postfix) => { + const words = ['a', `b${apos}${postfix}`, 'c']; + return lodashStable.map(words, (word) => + word[index ? 'toUpperCase' : 'toLowerCase'](), + ); + }); + expect(actual).toEqual(expected); + }); + }); + }); + + it('should not treat ordinal numbers as separate words', () => { + const ordinals = ['1st', '2nd', '3rd', '4th']; + + lodashStable.times(2, (index) => { + const expected = lodashStable.map(ordinals, (ordinal) => [ + ordinal[index ? 'toUpperCase' : 'toLowerCase'](), + ]); + const actual = lodashStable.map(expected, (expectedWords) => words(expectedWords[0])); + expect(actual).toEqual(expected); + }); + }); + + it('should prevent ReDoS', () => { + const largeWordLen = 50000; + const largeWord = 'A'.repeat(largeWordLen); + const maxMs = 1000; + const startTime = lodashStable.now(); + + expect(words(`${largeWord}ÆiouAreVowels`)).toEqual([largeWord, 'Æiou', 'Are', 'Vowels']); + + const endTime = lodashStable.now(); + const timeSpent = endTime - startTime; + + expect(timeSpent).toBeLessThan(maxMs); + }); + + it('should account for astral symbols', () => { + const string = `A ${leafs}, ${comboGlyph}, and ${rocket}`; + expect(words(string)).toEqual(['A', leafs, comboGlyph, 'and', rocket]); + }); + + it('should account for regional symbols', () => { + const pair = flag.match(/\ud83c[\udde6-\uddff]/g); + const regionals = pair.join(' '); + + expect(words(flag)).toEqual([flag]); + expect(words(regionals)).toEqual([pair[0], pair[1]]); + }); + + it('should account for variation selectors', () => { + expect(words(heart)).toEqual([heart]); + }); + + it('should match lone surrogates', () => { + const pair = hearts.split(''); + const surrogates = `${pair[0]} ${pair[1]}`; + + expect(words(surrogates)).toEqual([]); + }); +}); + +describe('wordsWithoutNumbers', () => { + it('should match words containing Latin Unicode letters', () => { + const expected = lodashStable.map(burredLetters, (letter) => [letter]); + const actual = lodashStable.map(burredLetters, (letter) => wordsWithNumbers(letter)); + expect(actual).toEqual(expected); + }); + + it('should work with compound words', () => { + expect(wordsWithNumbers('12ft')).toEqual(['12ft']); + expect(wordsWithNumbers('aeiouAreVowels')).toEqual(['aeiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('enable 6h format')).toEqual(['enable', '6h', 'format']); + expect(wordsWithNumbers('enable 24H format')).toEqual(['enable', '24H', 'format']); + expect(wordsWithNumbers('isISO8601')).toEqual(['is', 'ISO8601']); + expect(wordsWithNumbers('LETTERSAeiouAreVowels')).toEqual(['LETTERS', 'Aeiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('tooLegit2Quit')).toEqual(['too', 'Legit2', 'Quit']); + expect(wordsWithNumbers('walk500Miles')).toEqual(['walk500', 'Miles']); + expect(wordsWithNumbers('xhr2Request')).toEqual(['xhr2', 'Request']); + expect(wordsWithNumbers('XMLHttp')).toEqual(['XML', 'Http']); + expect(wordsWithNumbers('XmlHTTP')).toEqual(['Xml', 'HTTP']); + expect(wordsWithNumbers('XmlHttp')).toEqual(['Xml', 'Http']); + }); + + it('should work with compound words containing diacritical marks', () => { + expect(wordsWithNumbers('LETTERSÆiouAreVowels')).toEqual(['LETTERS', 'Æiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('æiouAreVowels')).toEqual(['æiou', 'Are', 'Vowels']); + expect(wordsWithNumbers('æiou2Consonants')).toEqual(['æiou2', 'Consonants']); + }); + + it('should not treat contractions as separate words', () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + lodashStable.each(["'", '\u2019'], (apos) => { + lodashStable.times(2, (index) => { + const actual = lodashStable.map(postfixes, (postfix) => { + const string = `a b${apos}${postfix} c`; + return wordsWithNumbers(string[index ? 'toUpperCase' : 'toLowerCase']()); + }); + const expected = lodashStable.map(postfixes, (postfix) => { + const words = ['a', `b${apos}${postfix}`, 'c']; + return lodashStable.map(words, (word) => + word[index ? 'toUpperCase' : 'toLowerCase'](), + ); + }); + expect(actual).toEqual(expected); + }); + }); + }); + + it('should not treat ordinal numbers as separate words', () => { + const ordinals = ['1st', '2nd', '3rd', '4th']; + + lodashStable.times(2, (index) => { + const expected = lodashStable.map(ordinals, (ordinal) => [ + ordinal[index ? 'toUpperCase' : 'toLowerCase'](), + ]); + const actual = lodashStable.map(expected, (expectedWords) => wordsWithNumbers(expectedWords[0])); + expect(actual).toEqual(expected); + }); + }); + + it('should prevent ReDoS', () => { + const largeWordLen = 50000; + const largeWord = 'A'.repeat(largeWordLen); + const maxMs = 1000; + const startTime = lodashStable.now(); + + expect(wordsWithNumbers(`${largeWord}ÆiouAreVowels`)).toEqual([largeWord, 'Æiou', 'Are', 'Vowels']); + + const endTime = lodashStable.now(); + const timeSpent = endTime - startTime; + + expect(timeSpent).toBeLessThan(maxMs); + }); + + it('should account for astral symbols', () => { + const string = `A ${leafs}, ${comboGlyph}, and ${rocket}`; + expect(wordsWithNumbers(string)).toEqual(['A', leafs, comboGlyph, 'and', rocket]); + }); + + it('should account for regional symbols', () => { + const pair = flag.match(/\ud83c[\udde6-\uddff]/g); + const regionals = pair.join(' '); + + expect(wordsWithNumbers(flag)).toEqual([flag]); + expect(wordsWithNumbers(regionals)).toEqual([pair[0], pair[1]]); + }); + + it('should account for variation selectors', () => { + expect(wordsWithNumbers(heart)).toEqual([heart]); + }); + + it('should match lone surrogates', () => { + const pair = hearts.split(''); + const surrogates = `${pair[0]} ${pair[1]}`; + + expect(wordsWithNumbers(surrogates)).toEqual([]); + }); +}); + +describe('snakeCase snakeCaseWithNumbers', () => { + const caseMethods = { + snakeCase, + snakeCaseWithNumbers, + }; + + lodashStable.each(['snakeCase', 'snakeCaseWithNumbers'], (caseName) => { + const methodName = caseName; + const func = caseMethods[methodName]; + + const strings = [ + 'foo bar', + 'Foo bar', + 'foo Bar', + 'Foo Bar', + 'FOO BAR', + 'fooBar', + '--foo-bar--', + '__foo_bar__', + ]; + + const converted = (function () { + switch (caseName) { + case 'snakeCase': + return 'foo_bar'; + case 'snakeCaseWithNumbers': + return 'foo_bar'; + } + })(); + + it(`\`_.${methodName}\` should convert \`string\` to ${caseName} case`, () => { + const actual = lodashStable.map(strings, (string) => { + const expected = caseName === 'start' && string === 'FOO BAR' ? string : converted; + return func(string) === expected; + }); + expect(actual).toEqual(lodashStable.map(strings, stubTrue)); + }); + + it(`\`_.${methodName}\` should handle double-converting strings`, () => { + const actual = lodashStable.map(strings, (string) => { + const expected = caseName === 'start' && string === 'FOO BAR' ? string : converted; + return func(func(string)) === expected; + }); + expect(actual).toEqual(lodashStable.map(strings, stubTrue)); + }); + + it(`\`_.${methodName}\` should remove contraction apostrophes`, () => { + const postfixes = ['d', 'll', 'm', 're', 's', 't', 've']; + + lodashStable.each(["'", '\u2019'], (apos) => { + const actual = lodashStable.map(postfixes, (postfix) => + func(`a b${apos}${postfix} c`), + ); + const expected = lodashStable.map(postfixes, (postfix) => { + switch (caseName) { + case 'snakeCase': + return `a_b${postfix}_c`; + case 'snakeCaseWithNumbers': + return `a_b${postfix}_c`; + } + }); + expect(actual).toEqual(expected); + }); + }); + + it(`\`_.${methodName}\` should remove Latin mathematical operators`, () => { + const actual = lodashStable.map(['\xd7', '\xf7'], func); + expect(actual).toEqual(['', '']); + }); + + it(`\`_.${methodName}\` should coerce \`string\` to a string`, () => { + const string = 'foo bar'; + expect(func(Object(string))).toBe(converted); + expect(func({toString: lodashStable.constant(string)})).toBe(converted); + }); + + it(`\`_.${methodName}\` should return an empty string for empty values`, () => { + const values = [, null, undefined, '']; + const expected = lodashStable.map(values, stubString); + + const actual = lodashStable.map(values, (value, index) => + index ? func(value) : func(), + ); + + expect(actual).toEqual(expected); + }); + }); +}); \ No newline at end of file diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 84371e40b3..576bc32478 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -14,37 +14,39 @@ const {isBlank} = require("../../src/warehouse/config/helpers.js"); const version = "v0"; const integrations = [ - "rs", - "bq", - "postgres", - "clickhouse", - "snowflake", - "mssql", - "azure_synapse", - "deltalake", - "azure_datalake", - "s3_datalake", - "gcs_datalake", + "rs", + "bq", + "postgres", + "clickhouse", + "snowflake", + "mssql", + "azure_synapse", + "deltalake", + "azure_datalake", + "s3_datalake", + "gcs_datalake", ]; const transformers = integrations.map(integration => - require(`../../src/${version}/destinations/${integration}/transform`) + require(`../../src/${version}/destinations/${integration}/transform`) ); const eventTypes = ["track", "identify", "page", "screen", "group", "alias"]; // get key of user set properties in the event // eg. for identify call, user sets the custom properties inside traits const propsKeyMap = { - track: "properties", - page: "properties", - screen: "properties", - identify: "traits", - group: "traits", - alias: "traits" + track: "properties", + page: "properties", + screen: "properties", + + identify: "traits", + group: "traits", + alias: "traits" }; + const integrationCasedString = (integration, str) => { - if (integration === "snowflake") { - return str.toUpperCase(); - } - return str; + if (integration === "snowflake") { + return str.toUpperCase(); + } + return str; }; describe("event types", () => { @@ -1224,53 +1226,8 @@ describe("Destination config", () => { }); }); - describe('allowUsersContextTraits, allowEventContextTraits, underscoreDivideNumbers', () => { + describe('allowUsersContextTraits, underscoreDivideNumbers', () => { describe("old destinations", () => { - it('without allowEventContextTraits', () => { - transformers.forEach((transformer, index) => { - const event = { - destination: { - Config: { - allowEventContextTraits: true - }, - }, - message: { - context: { - traits: { - city: "Disney", - country: "USA", - email: "mickey@disney.com", - firstname: "Mickey" - } - }, - event: "button clicked", - type: "track", - }, - request: { - query: { - whSchemaVersion: "v1" - } - } - } - const output = transformer.process(event); - const events = [output[0], output[1]]; - const traitsToCheck = { - 'city': 'Disney', - 'country': 'USA', - 'email': 'mickey@disney.com', - 'firstname': 'Mickey' - }; - events.forEach(event => { - Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(output[0].data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); - expect(output[1].data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); - expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); - }); - }); - }); - }); - it('with allowUsersContextTraits', () => { transformers.forEach((transformer, index) => { const event = { @@ -1352,47 +1309,7 @@ describe("Destination config", () => { }); }); describe("new destinations", () => { - it('without allowEventContextTraits', () => { - transformers.forEach((transformer, index) => { - const event = { - destination: { - Config: {}, - }, - message: { - context: { - traits: { - city: "Disney", - country: "USA", - email: "mickey@disney.com", - firstname: "Mickey" - } - }, - event: "button clicked", - type: "track", - }, - request: { - query: { - whSchemaVersion: "v1" - } - } - } - const output = transformer.process(event); - const traitsToCheck = { - 'city': 'Disney', - 'country': 'USA', - 'email': 'mickey@disney.com', - 'firstname': 'Mickey' - }; - Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(output[0].data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); - expect(output[1].data).not.toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); - expect(output[1].metadata.columns).not.toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); - }); - }); - }); - - it('without allowUsersContextTraits', () => { + it('without allowUsersContextTraits', () => { transformers.forEach((transformer, index) => { const event = { destination: { @@ -1586,421 +1503,649 @@ describe("isBlank", () => { }); describe("transformColumnName", () => { - describe('with Blendo Casing', () => { - const testCases = [ - { - description: 'should convert special characters other than "\\" or "$" to underscores', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: 'column@Name#1', - expected: 'column_name_1', - }, - { - description: 'should add underscore if name does not start with an alphabet or underscore', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: '1CComega', - expected: '_1ccomega', - }, - { - description: 'should handle non-ASCII characters by converting to underscores', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: 'Cízǔ', - expected: 'c_z_', - }, - { - description: 'should preserve "\\" and "$" characters', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: 'path_to_$1,00,000', - expected: 'path_to_$1_00_000', - }, - { - description: 'should transform CamelCase123Key to camelcase123key', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: 'CamelCase123Key', - expected: 'camelcase123key', - }, - { - description: 'should handle a mix of characters, numbers, and special characters', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: 'CamelCase123Key_with$special\\chars', - expected: 'camelcase123key_with$special\\chars', - }, - { - description: 'should handle names starting with a number', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: '1Column', - expected: '_1column', - }, - { - description: 'should limit length to 63 characters for postgres provider', - options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, - input: 'a'.repeat(70), - expected: 'a'.repeat(63), - }, - ]; - testCases.forEach(({description, options, input, expected}) => { - it(description, () => { - const result = transformColumnName(options, input); - expect(result).toBe(expected); - }); - }); + describe('with Blendo Casing', () => { + const testCases = [ + { + description: 'should convert special characters other than "\\" or "$" to underscores', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'column@Name$1', + expected: 'column_name$1', + }, + { + description: 'should add underscore if name does not start with an alphabet or underscore', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: '1CComega', + expected: '_1ccomega', + }, + { + description: 'should handle non-ASCII characters by converting to underscores', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'Cízǔ', + expected: 'c_z_', + }, + { + description: 'should transform CamelCase123Key to camelcase123key', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'CamelCase123Key', + expected: 'camelcase123key', + }, + { + description: 'should preserve "\\" and "$" characters', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'path to $1,00,000', + expected: 'path_to_$1_00_000', + }, + { + description: 'should handle a mix of characters, numbers, and special characters', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'CamelCase123Key_with$special\\chars', + expected: 'camelcase123key_with$special\\chars', + }, + { + description: 'should limit length to 63 characters for postgres provider', + options: {integrationOptions: {useBlendoCasing: true}, provider: 'postgres'}, + input: 'a'.repeat(70), + expected: 'a'.repeat(63), + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformColumnName(options, input); + expect(result).toBe(expected); + }); }); + }); - describe('without Blendo Casing', () => { - const testCases = [ - { - description: 'should remove symbols and join continuous letters and numbers with a single underscore', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: '&4yasdfa(84224_fs9##_____*3q', - expected: '_4_yasdfa_84224_fs_9_3_q', - }, - { - description: 'should transform "omega" to "omega"', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'omega', - expected: 'omega', - }, - { - description: 'should transform "omega v2" to "omega_v_2"', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'omega v2', - expected: 'omega_v_2', - }, - { - description: 'should prepend underscore if name starts with a number', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: '9mega', - expected: '_9_mega', - }, - { - description: 'should remove trailing special characters', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'mega&', - expected: 'mega', - }, - { - description: 'should replace special character in the middle with underscore', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'ome$ga', - expected: 'ome_ga', - }, - { - description: 'should not remove trailing $ character', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'omega$', - expected: 'omega', - }, - { - description: 'should handle spaces and special characters by converting to underscores', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'ome_ ga', - expected: 'ome_ga', - }, - { - description: 'should handle multiple underscores and hyphens by reducing to single underscores', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: '9mega________-________90', - expected: '_9_mega_90', - }, - { - description: 'should handle non-ASCII characters by converting them to underscores', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'Cízǔ', - expected: 'c_z', - }, - { - description: 'should transform CamelCase123Key to camel_case_123_key', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'CamelCase123Key', - expected: 'camel_case_123_key', - }, - { - description: 'should handle numbers and commas in the input', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'path to $1,00,000', - expected: 'path_to_1_00_000', - }, - { - description: 'should return an empty string if input contains no valid characters', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: '@#$%', - expected: '', - }, - { - description: 'should remove underscores between letters and numbers when underscoreDivideNumbers is false', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: false - }, - input: 'test123', - expected: 'test123', - }, - { - description: 'should keep underscores between letters and numbers when underscoreDivideNumbers is true', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'test123', - expected: 'test_123', - }, - { - description: 'should correctly handle multiple underscore-number sequences when underscoreDivideNumbers is false', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: false - }, - input: 'abc123def456', - expected: 'abc123_def456', - }, - { - description: 'should avoid adding extra underscores when underscoreDivideNumbers is false', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: false - }, - input: 'abc_123_def_456', - expected: 'abc123_def456', - }, - { - description: 'should keep multiple underscore-number sequences when underscoreDivideNumbers is true', - options: { - integrationOptions: {useBlendoCasing: false}, - provider: 'postgres', - underscoreDivideNumbers: true - }, - input: 'abc123def456', - expected: 'abc_123_def_456', - }, - ]; - testCases.forEach(({description, options, input, expected}) => { - it(description, () => { - const result = transformColumnName(options, input); - expect(result).toBe(expected); - }); - }); + describe('without Blendo Casing (underscoreDivideNumbers=true)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4_yasdfa_84224_fs_9_3_q', + }, + { + description: 'should transform "omega" to "omega"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega v2', + expected: 'omega_v_2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '9mega', + expected: '_9_mega', + }, + { + description: 'should remove trailing special characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '9mega________-________90', + expected: '_9_mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'CamelCase123Key', + expected: 'camel_case_123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'test123', + expected: 'test_123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'abc123def456', + expected: 'abc_123_def_456', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'abc_123_def_456', + expected: 'abc_123_def_456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformColumnName(options, input); + expect(result).toBe(expected); + }); }); + }); + + describe('without Blendo Casing (underscoreDivideNumbers=false)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4yasdfa_84224_fs9_3q', + }, + { + description: 'should transform "omega" to "omega"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'omega v2', + expected: 'omega_v2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '9mega', + expected: '_9mega', + }, + { + description: 'should remove trailing special characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: true + }, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '9mega________-________90', + expected: '_9mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'CamelCase123Key', + expected: 'camel_case123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'test123', + expected: 'test123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'abc123def456', + expected: 'abc123_def456', + }, + { + description: 'should keep multiple underscore-number sequences', + options: { + integrationOptions: {useBlendoCasing: false}, + provider: 'postgres', + underscoreDivideNumbers: false + }, + input: 'abc_123_def_456', + expected: 'abc_123_def_456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformColumnName(options, input); + expect(result).toBe(expected); + }); + }); + }); }) describe("transformTableName", () => { - describe('with Blendo Casing', () => { - const testCases = [ - { - description: 'should convert name to Blendo casing (lowercase) when Blendo casing is enabled', - options: {integrationOptions: {useBlendoCasing: true}}, - input: 'TableName123', - expected: 'tablename123', - }, - { - description: 'should trim spaces and convert to Blendo casing (lowercase) when Blendo casing is enabled', - options: {integrationOptions: {useBlendoCasing: true}}, - input: ' TableName ', - expected: 'tablename', - }, - { - description: 'should return an empty string when input is empty and Blendo casing is enabled', - options: {integrationOptions: {useBlendoCasing: true}}, - input: '', - expected: '', - }, - { - description: 'should handle names with special characters and convert to Blendo casing (lowercase)', - options: {integrationOptions: {useBlendoCasing: true}}, - input: 'Table@Name!', - expected: 'table@name!', - }, - { - description: 'should convert a mixed-case name to Blendo casing (lowercase) when Blendo casing is enabled', - options: {integrationOptions: {useBlendoCasing: true}}, - input: 'CaMeLcAsE', - expected: 'camelcase', - }, - { - description: 'should keep an already lowercase name unchanged with Blendo casing enabled', - options: {integrationOptions: {useBlendoCasing: true}}, - input: 'lowercase', - expected: 'lowercase', - }, - ]; - testCases.forEach(({description, options, input, expected}) => { - it(description, () => { - const result = transformTableName(options, input); - expect(result).toBe(expected); - }); - }); + describe('with Blendo Casing', () => { + const testCases = [ + { + description: 'should convert name to Blendo casing (lowercase) when Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'TableName123', + expected: 'tablename123', + }, + { + description: 'should trim spaces and convert to Blendo casing (lowercase) when Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: ' TableName ', + expected: 'tablename', + }, + { + description: 'should return an empty string when input is empty and Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: '', + expected: '', + }, + { + description: 'should handle names with special characters and convert to Blendo casing (lowercase)', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'Table@Name!', + expected: 'table@name!', + }, + { + description: 'should convert a mixed-case name to Blendo casing (lowercase) when Blendo casing is enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'CaMeLcAsE', + expected: 'camelcase', + }, + { + description: 'should keep an already lowercase name unchanged with Blendo casing enabled', + options: {integrationOptions: {useBlendoCasing: true}}, + input: 'lowercase', + expected: 'lowercase', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformTableName(options, input); + expect(result).toBe(expected); + }); }); + }); - describe('without Blendo Casing', () => { - const testCases = [ - { - description: 'should remove symbols and join continuous letters and numbers with a single underscore', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: '&4yasdfa(84224_fs9##_____*3q', - expected: '_4_yasdfa_84224_fs_9_3_q', - }, - { - description: 'should transform "omega" to "omega"', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'omega', - expected: 'omega', - }, - { - description: 'should transform "omega v2" to "omega_v_2"', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'omega v2', - expected: 'omega_v_2', - }, - { - description: 'should prepend underscore if name starts with a number', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: '9mega', - expected: '_9_mega', - }, - { - description: 'should remove trailing special characters', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'mega&', - expected: 'mega', - }, - { - description: 'should replace special character in the middle with underscore', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'ome$ga', - expected: 'ome_ga', - }, - { - description: 'should not remove trailing $ character', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'omega$', - expected: 'omega', - }, - { - description: 'should handle spaces and special characters by converting to underscores', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'ome_ ga', - expected: 'ome_ga', - }, - { - description: 'should handle multiple underscores and hyphens by reducing to single underscores', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: '9mega________-________90', - expected: '_9_mega_90', - }, - { - description: 'should handle non-ASCII characters by converting them to underscores', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'Cízǔ', - expected: 'c_z', - }, - { - description: 'should transform CamelCase123Key to camel_case_123_key', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'CamelCase123Key', - expected: 'camel_case_123_key', - }, - { - description: 'should handle numbers and commas in the input', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'path to $1,00,000', - expected: 'path_to_1_00_000', - }, - { - description: 'should return an empty string if input contains no valid characters', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: '@#$%', - expected: '', - }, - { - description: 'should remove underscores between letters and numbers when underscoreDivideNumbers is false', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, - input: 'test123', - expected: 'test123', - }, - { - description: 'should keep underscores between letters and numbers when underscoreDivideNumbers is true', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'test123', - expected: 'test_123', - }, - { - description: 'should correctly handle multiple underscore-number sequences when underscoreDivideNumbers is false', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, - input: 'abc123def456', - expected: 'abc123_def456', - }, - { - description: 'should avoid adding extra underscores when underscoreDivideNumbers is false', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, - input: 'abc_123_def_456', - expected: 'abc123_def456', - }, - { - description: 'should keep multiple underscore-number sequences when underscoreDivideNumbers is true', - options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, - input: 'abc123def456', - expected: 'abc_123_def_456', - }, - ]; - testCases.forEach(({description, options, input, expected}) => { - it(description, () => { - const result = transformTableName(options, input); - expect(result).toBe(expected); - }); - }); + describe('without Blendo Casing (underscoreDivideNumbers=true)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4_yasdfa_84224_fs_9_3_q', + }, + { + description: 'should transform "omega" to "omega"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega v2', + expected: 'omega_v_2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '9mega', + expected: '_9_mega', + }, + { + description: 'should remove trailing special characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '9mega________-________90', + expected: '_9_mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'CamelCase123Key', + expected: 'camel_case_123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'test123', + expected: 'test_123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'abc123def456', + expected: 'abc_123_def_456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformTableName(options, input); + expect(result).toBe(expected); + }); + }); + }); + + describe('without Blendo Casing (underscoreDivideNumbers=false)', () => { + const testCases = [ + { + description: 'should remove symbols and join continuous letters and numbers with a single underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '&4yasdfa(84224_fs9##_____*3q', + expected: '_4yasdfa_84224_fs9_3q', + }, + { + description: 'should transform "omega" to "omega"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'omega', + expected: 'omega', + }, + { + description: 'should transform "omega v2" to "omega_v_2"', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'omega v2', + expected: 'omega_v2', + }, + { + description: 'should prepend underscore if name starts with a number', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '9mega', + expected: '_9mega', + }, + { + description: 'should remove trailing special characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'mega&', + expected: 'mega', + }, + { + description: 'should replace special character in the middle with underscore', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'ome$ga', + expected: 'ome_ga', + }, + { + description: 'should not remove trailing $ character', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: true}, + input: 'omega$', + expected: 'omega', + }, + { + description: 'should handle spaces and special characters by converting to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'ome_ ga', + expected: 'ome_ga', + }, + { + description: 'should handle multiple underscores and hyphens by reducing to single underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '9mega________-________90', + expected: '_9mega_90', + }, + { + description: 'should handle non-ASCII characters by converting them to underscores', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'Cízǔ', + expected: 'c_z', + }, + { + description: 'should transform CamelCase123Key to camel_case_123_key', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'CamelCase123Key', + expected: 'camel_case123_key', + }, + { + description: 'should handle numbers and commas in the input', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'path to $1,00,000', + expected: 'path_to_1_00_000', + }, + { + description: 'should return an empty string if input contains no valid characters', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: '@#$%', + expected: '', + }, + { + description: 'should keep underscores between letters and numbers', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'test123', + expected: 'test123', + }, + { + description: 'should keep multiple underscore-number sequences', + options: {integrationOptions: {useBlendoCasing: false}, underscoreDivideNumbers: false}, + input: 'abc123def456', + expected: 'abc123_def456', + }, + ]; + testCases.forEach(({description, options, input, expected}) => { + it(description, () => { + const result = transformTableName(options, input); + expect(result).toBe(expected); + }); }); + }); }); \ No newline at end of file diff --git a/test/integrations/destinations/gcs_datalake/processor/data.ts b/test/integrations/destinations/gcs_datalake/processor/data.ts index dca1ad749a..26f438758d 100644 --- a/test/integrations/destinations/gcs_datalake/processor/data.ts +++ b/test/integrations/destinations/gcs_datalake/processor/data.ts @@ -63,7 +63,6 @@ export const data = [ tableSuffix: '', timeWindowLayout: '2006/01/02/15', allowUsersContextTraits: true, - allowEventContextTraits: true, underscoreDivideNumbers: true, }, Enabled: true,