Skip to content

Commit

Permalink
split table options into separate properties
Browse files Browse the repository at this point in the history
  • Loading branch information
pdesmarets committed Oct 5, 2019
1 parent 701baa8 commit 046203b
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 70 deletions.
47 changes: 47 additions & 0 deletions adapter/0.1.33.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright © 2016-2018 by IntegrIT S.A. dba Hackolade. All rights reserved.
*
* The copyright to the computer software herein is the property of IntegrIT S.A.
* The software may be used and/or copied only with the written permission of
* IntegrIT S.A. or in accordance with the terms and conditions stipulated in
* the agreement/contract under which the software has been supplied.
*
* {
* "add": {
* "entity": [<names of new property>],
* "container": [<names of new property>],
* "model": [<names of new property>],
* "view": [<names of new property>],
* "field": {
* "<type>": [<names of new property>]
* }
* },
* "remove": {
* "entity": [<names of new property>],
* "container": [<names of new property>],
* "model": [<names of new property>],
* "view": [<names of new property>],
* "field": {
* "<type>": [<names of new property>]
* }
* },
* "modify": {
* "entity": [
* {
* "from": { <properties that identify record> },
* "to": { <properties that need to be changed> }
* }
* ],
* "container": [],
* "model": [],
* "view": [],
* "field": []
* },
* }
*/

{
"modify": {
"entity": ["transformTableOptionsFromStringToObject"]
}
}
5 changes: 4 additions & 1 deletion forward_engineering/helpers/generalHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const cacheResult = (method) => {
};

const getFieldLevelConfig = cacheResult(() => getConfig(path.join("properties_pane", "field_level", "fieldLevelConfig.json")));
const entityLevelConfig = cacheResult(() => getConfig(path.join("properties_pane", "entity_level", "entityLevelConfig.json")));

const getTypesConfig = cacheResult(() => {
const getName = typeFile => typeFile.replace(/\.json/, "");
Expand All @@ -62,6 +63,7 @@ const getTypesConfig = cacheResult(() => {
});

const getTypeConfig = (type) => getTypesConfig()[type];
const getEntityLevelConfig = () => entityLevelConfig();

const getFieldConfig = (type, property) => {
const fieldLevelConfig = getFieldLevelConfig().structure;
Expand Down Expand Up @@ -130,5 +132,6 @@ module.exports = {
getTypeConfig,
getNameWithKeyspace,
eachField,
canTypeHaveSubtype
canTypeHaveSubtype,
getEntityLevelConfig,
};
196 changes: 196 additions & 0 deletions forward_engineering/helpers/parseTableOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
const NUMERIC = 'numeric';
const TEXT = 'text';
const DETAILS = 'details';
const CHECKBOX = 'checkbox';

const OTHER = 'otherProperties';
const CACHING = 'caching';
const specialOptions = [CACHING, OTHER];

const getStringStart = str => str === '' ? '\nWITH' : ' AND';
const changeQuotes = str => String(str || '').replace(/[\"\`]/g, '\'');

const tableOptionsHashMap = {
localReadRepairChance: 'dclocal_read_repair_chance',
readRepairChance: 'read_repair_chance',
gcGraceSeconds: 'gc_grace_seconds',
bloomFilterFalsePositiveChance: 'bloom_filter_fp_chance',
defaultTtl: 'default_time_to_live',
speculativeRetry: 'speculative_retry',
minIndexInterval: 'min_index_interval',
maxIndexInterval: 'max_index_interval',
crcCheckChance: 'crc_check_chance',
memtableFlushPeriod: 'memtable_flush_period_in_ms',
}

const convertKeywordToTableOptionName = keyword => {
if (tableOptionsHashMap.hasOwnProperty(keyword)) {
return tableOptionsHashMap[keyword];
}

return keyword;
}

const transformOption = (option) => {
if (specialOptions.includes(option.propertyKeyword)) {
return transformSpecialOption(option);
}

return transformOptionByPropertyType(option);

};

const transformSpecialOption = option => {
switch (option.propertyKeyword) {
case CACHING: return transformCachingOption(option);
case OTHER: return transformOtherOptions(option);
default: return null;
}
}

const transformOptionByPropertyType = option => {
switch (option.propertyType) {
case TEXT: return transformTextOption(option);
case CHECKBOX: return transformBooleanOption(option);
case NUMERIC: return transformNumericOption(option);
case DETAILS: return transformDetailsOptions(option);
default: return null;
}
}

const transformTextOption = option =>
`${convertKeywordToTableOptionName(option['propertyKeyword'])} = '${option.value}'`;

const transformNumericOption = option =>
`${convertKeywordToTableOptionName(option['propertyKeyword'])} = ${option.value}`;

const transformDetailsOptions = option => {
const getStringValue = value => {
if (typeof value === 'object') {
return JSON.stringify(option.value);
}

return value;
}
const stringValue = getStringValue(option.value);
const trimmedValue = stringValue.replace(/\n/g, '');
return `${convertKeywordToTableOptionName(option['propertyKeyword'])} = ${changeQuotes(trimmedValue)}`;
}

const transformOtherOptions = option => {
const subOptionArray = option.value;
return subOptionArray
.reduce((optionString, option) => {
const { name, value } = option;
if (!name || !value) {
return optionString;
}

const start = optionString === '' ? '' : ' AND';
return optionString.concat(`${start} ${name} = '${value}'\n`);
}, '')
.replace(/\n$/, '');
}

const transformBooleanOption = option => {
const keyword = option['propertyKeyword'];
if (!Boolean(option.value)) {
return null;
}

if (keyword === 'cdc') {
return 'cdc = TRUE';
}

if (keyword === 'compactStorage') {
return 'COMPACT STORAGE';
}

return null;
}

const transformCachingOption = option => {
const validateKeys = value => allowedValues.includes(value) ? value : null;
const validateRows = value => {
if (allowedValues.includes(value)) {
return value;
}

if (!isNaN(value)) {
return Number(value);
}

return null;
};
const createValueObject = (keys, rows) => Object.assign(
{},
keys && { keys },
rows && { rows_per_partition: rows }
);
const allowedValues = ['ALL', 'NONE'];
const keys = validateKeys(option.value['keys']);
const rows = validateRows(option.value['rowsPerPartition']);
if (!keys && !rows) {
return null;
}

const stringValue = JSON.stringify(createValueObject(keys, rows));
return `caching = ${changeQuotes(stringValue)}`;
}

const generateOptionsStringReducer = (str, option) => {
if (!option.value && typeof option.value !== 'number') {
return str;
}

const optionString = transformOption(option);
if (!optionString) {
return str;
}

const start = getStringStart(str);
return str.concat(`${start} ${optionString}\n`);
}

const addCommentToOptionString = (optionString, comment) => {
if (comment) {
const start = getStringStart(optionString);
return optionString.concat(`${start} comment = '${comment}'\n`);
}

return optionString;
}

const addId = (tableId, options) => {
if (!tableId) {
return options;
}

const start = getStringStart(options);
return options.concat(`${start} ID = '${tableId}'\n`);
}

const addClustering = (clusteringKeys, clusteringKeysHash, options) => {
if (!clusteringKeys.length) {
return options;
}

const fields = clusteringKeys.map((key) => {
const { keyId, type } = key;
const fieldName = clusteringKeysHash[keyId];
const order = type === 'descending' ? 'DESC' : 'ASC';
return `"${fieldName}" ${order}`;
}).join(', ');
const start = getStringStart(options);
return options.concat(`${start} CLUSTERING ORDER BY (${fields})\n`);
}

module.exports = {
parseTableOptions(options, comment) {
const optionString = options.reduce(generateOptionsStringReducer, '');
const optionsWithComment = addCommentToOptionString(optionString, comment);
return optionsWithComment;
},
addId,
addClustering,
};
67 changes: 22 additions & 45 deletions forward_engineering/helpers/tableHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const {
} = require('./generalHelper');
const { getColumnDefinition } = require('./columnHelper');
const { getNamesByIds } = require('./schemaHelper');
const { getEntityLevelConfig } = require('./generalHelper');
const { parseTableOptions, addId, addClustering } = require('./parseTableOptions');

module.exports = {
getTableStatement({
Expand Down Expand Up @@ -40,7 +42,7 @@ module.exports = {
tableName,
getColumnDefinition(tableData.properties || {}, udtTypeMap),
getPrimaryKeyList(partitionKeysHash, clusteringKeysHash),
getOptions(clusteringKeys, clusteringKeysHash, tableId, tableComment, tableOptions)
getOptions(clusteringKeys, clusteringKeysHash, tableId, tableOptions, tableComment)
);
}
};
Expand Down Expand Up @@ -99,53 +101,28 @@ const getClusteringKeys = (clusteringKeysHash) => {
}
};

const getOptions = (clusteringKeys, clusteringKeysHash, id, comment, tableOptions) => {
const changeQuotes = (str) => String(str || '').replace(/[\"\`]/g, '\'');
const getClusteringOrder = (clusteringKeys, clusteringKeysHash) => {
const order = (order) => (order === 'ascending') ? 'ASC' : 'DESC';
const orderString = clusteringKeys.map(key => {
const name = clusteringKeysHash[key.keyId];

if (name) {
return `"${name}" ${order(key.type)}`;
}
}).filter(key => key).join(', ');

if (orderString) {
return `CLUSTERING ORDER BY (${orderString})`;
} else {
return false;
}
};
const parseTableOptions = (tableOptions) => (tableOptions || "")
.replace(/;$/, "")
.split('AND')
.map(option => String(option || '').trim())
.map(changeQuotes)
.filter(option => option);

let options = [];
const clusteringOrder = getClusteringOrder(clusteringKeys, clusteringKeysHash);
const hasId = id && !/id\=/gi.test(tableOptions);
const hasComment = comment && !/comments\=/gi.test(tableOptions);

if (clusteringOrder) {
options.push(clusteringOrder);
const seedOptionsWithValues = (options, valueObject) => options.map(option => {
const value = valueObject[option['propertyKeyword']];
if (!value && typeof value !== 'number') {
return option;
}

if (hasId) {
options.push(`ID='${id}'`);
}
return Object.assign({}, option, { value });
});

if (hasComment) {
options.push(`comment='${comment}'`);
}
const getOptionsFromTab = config => {
const optionsBlock = config.structure.find(prop => prop.propertyName === 'Options');
return optionsBlock.structure;
}

options = options.concat(parseTableOptions(tableOptions));
const getOptions = (clusteringKeys, clusteringKeysHash, tableId, tableOptions, comment) => {
const [detailsTab] = getEntityLevelConfig();
const configOptions = getOptionsFromTab(detailsTab);
const optionsWithValues = seedOptionsWithValues(configOptions, tableOptions);
const optionsString = addId(
tableId,
addClustering(clusteringKeys, clusteringKeysHash, parseTableOptions(optionsWithValues, comment))
);

if (options.length) {
return `\nWITH ${ options.join("\n" + tab("AND ")) }`;
} else {
return "";
}
return optionsString ? optionsString.replace(/\n$/, '') : '';
};
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "Cassandra",
"version": "0.1.32",
"versionDate": "2019-07-29",
"version": "0.1.33",
"versionDate": "2019-10-05",
"author": "hackolade",
"engines": {
"hackolade": "3.4.0",
"hackolade": "3.4.12",
"hackoladePlugin": "1.2.0"
},
"contributes": {
Expand Down
2 changes: 1 addition & 1 deletion properties_pane/defaultData.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"collectionName": "New table",
"collectionUsers": [],
"collation": {},
"tableOptions": ""
"tableOptions": {}
},
"field": {
"name": "New column"
Expand Down
Loading

0 comments on commit 046203b

Please sign in to comment.