@finos/legend-application-studio
Version:
Legend Studio application core
204 lines • 9.25 kB
JavaScript
/**
* Copyright (c) 2020-present, Goldman Sachs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { addDays, assertErrorThrown, formatDate, Randomizer, UnsupportedOperationError, isNonNullable, filterByType, } from '@finos/legend-shared';
import { PrimitiveType, PRIMITIVE_TYPE, Class, getAllClassProperties, DATE_FORMAT, DATE_TIME_FORMAT, classHasCycle, TableAlias, Table, Column, VarChar, Char, VarBinary, TinyInt, Float, Timestamp, Binary, Bit, Other, Numeric, Decimal, Double, Integer, Real, SmallInt, Date as ColumnDate, SemiStructured, Json, MILESTONING_VERSION_PROPERTY_SUFFIX, } from '@finos/legend-graph';
import { CLASS_PROPERTY_TYPE, getClassPropertyType, } from './ModelClassifierUtils.js';
import { DEFAULT_TAB_SIZE } from '@finos/legend-application';
import { XMLBuilder } from 'fast-xml-parser';
import { stringify as YAML_stringify } from 'yaml';
export const createMockPrimitiveProperty = (primitiveType, propertyName) => {
const randomizer = new Randomizer();
switch (primitiveType.name) {
case PRIMITIVE_TYPE.BOOLEAN:
return randomizer.getRandomItemInCollection([true, false]) ?? true;
case PRIMITIVE_TYPE.FLOAT:
return randomizer.getRandomFloat();
case PRIMITIVE_TYPE.DECIMAL:
return randomizer.getRandomDouble();
case PRIMITIVE_TYPE.NUMBER:
case PRIMITIVE_TYPE.INTEGER:
return randomizer.getRandomWholeNumber(100);
// NOTE that `Date` is the umbrella type that comprises `StrictDate` and `DateTime`, but for simplicity, we will generate `Date` as `StrictDate`
case PRIMITIVE_TYPE.DATE:
case PRIMITIVE_TYPE.STRICTDATE:
return formatDate(randomizer.getRandomDate(new Date(Date.now()), addDays(Date.now(), 100)), DATE_FORMAT);
case PRIMITIVE_TYPE.DATETIME:
return formatDate(randomizer.getRandomDate(new Date(Date.now()), addDays(Date.now(), 100)), DATE_TIME_FORMAT);
case PRIMITIVE_TYPE.STRING:
default:
return `${propertyName} ${randomizer.getRandomWholeNumber(100)}`;
}
};
export const createMockEnumerationProperty = (enumeration) => new Randomizer().getRandomItemInCollection(enumeration.values)?.name ?? '';
export const createMockClassInstance = (_class, traverseNonRequiredProperties = false, depth = 0) => {
const properties = traverseNonRequiredProperties
? getAllClassProperties(_class, true)
: getAllClassProperties(_class, true).filter((p) => p.multiplicity.lowerBound);
const propertyNames = properties.map((property) => property.name);
const filteredProperties = properties.filter((prop) => prop.name.endsWith(MILESTONING_VERSION_PROPERTY_SUFFIX.ALL_VERSIONS) ||
(!propertyNames.includes(prop.name + MILESTONING_VERSION_PROPERTY_SUFFIX.ALL_VERSIONS) &&
!prop.name.endsWith(MILESTONING_VERSION_PROPERTY_SUFFIX.ALL_VERSIONS_IN_RANGE)));
const mockData = {};
filteredProperties.forEach((property) => {
const propertyType = property.genericType.value.rawType;
let propertyMockData;
switch (getClassPropertyType(propertyType)) {
case CLASS_PROPERTY_TYPE.PRIMITIVE:
propertyMockData = createMockPrimitiveProperty(propertyType, property.name);
break;
case CLASS_PROPERTY_TYPE.ENUMERATION:
propertyMockData = createMockEnumerationProperty(propertyType);
break;
case CLASS_PROPERTY_TYPE.CLASS:
if (depth > 0) {
propertyMockData = createMockClassInstance(propertyType, traverseNonRequiredProperties, depth - 1);
}
break;
default:
break;
}
if (propertyMockData) {
mockData[property.name] =
property.multiplicity.upperBound === undefined ||
property.multiplicity.upperBound >= 2
? [propertyMockData]
: propertyMockData;
}
});
return mockData;
};
export const createMockDataForClass = (element, maxDepth = 100, depthForCycle = 3) => {
const depth = classHasCycle(element, {
traverseNonRequiredProperties: true,
})
? Math.max(depthForCycle, 0)
: Math.max(maxDepth, 0);
return createMockClassInstance(element, true, depth);
};
export var CLASS_MOCK_DATA_GENERATION_FORMAT;
(function (CLASS_MOCK_DATA_GENERATION_FORMAT) {
CLASS_MOCK_DATA_GENERATION_FORMAT["JSON"] = "JSON";
CLASS_MOCK_DATA_GENERATION_FORMAT["XML"] = "XML";
CLASS_MOCK_DATA_GENERATION_FORMAT["YAML"] = "YAML";
})(CLASS_MOCK_DATA_GENERATION_FORMAT || (CLASS_MOCK_DATA_GENERATION_FORMAT = {}));
export const createMockDataForClassWithFormat = (element, format, maxDepth = 100, depthForCycle = 3) => {
const depth = classHasCycle(element, {
traverseNonRequiredProperties: true,
})
? Math.max(depthForCycle, 0)
: Math.max(maxDepth, 0);
const obj = createMockClassInstance(element, true, depth);
switch (format) {
case CLASS_MOCK_DATA_GENERATION_FORMAT.JSON:
return JSON.stringify(obj, undefined, DEFAULT_TAB_SIZE);
case CLASS_MOCK_DATA_GENERATION_FORMAT.XML: {
return new XMLBuilder({
indentBy: ' '.repeat(DEFAULT_TAB_SIZE),
format: true,
}).build(obj);
}
case CLASS_MOCK_DATA_GENERATION_FORMAT.YAML:
return YAML_stringify(obj, { indent: DEFAULT_TAB_SIZE });
default:
throw new UnsupportedOperationError(`Can't create mock data for class with format '${format}'`);
}
};
export const getPrimitiveTypeFromRelationalType = (type) => {
if (type instanceof VarChar ||
type instanceof Char ||
type instanceof VarBinary ||
type instanceof Binary ||
type instanceof Bit ||
type instanceof Other) {
return PrimitiveType.STRING;
}
else if (type instanceof Numeric) {
return PrimitiveType.NUMBER;
}
else if (type instanceof Decimal) {
return PrimitiveType.DECIMAL;
}
else if (type instanceof Double ||
type instanceof Integer ||
type instanceof Real ||
type instanceof SmallInt ||
type instanceof TinyInt) {
return PrimitiveType.INTEGER;
}
else if (type instanceof Float) {
return PrimitiveType.FLOAT;
}
else if (type instanceof ColumnDate) {
return PrimitiveType.DATE;
}
else if (type instanceof Timestamp) {
return PrimitiveType.DATETIME;
}
return undefined;
};
export const createMockDataForColumn = (col, isPrimaryKey, idx) => {
const type = col.type;
if ((type instanceof Double ||
type instanceof Integer ||
type instanceof Real ||
type instanceof SmallInt ||
type instanceof TinyInt) &&
isPrimaryKey &&
idx) {
return idx.toString();
}
const primitive = getPrimitiveTypeFromRelationalType(type);
if (primitive) {
return createMockPrimitiveProperty(primitive, col.name).toString();
}
else if (type instanceof Json || type instanceof SemiStructured) {
return '{}';
}
return undefined;
};
export const createMockDataForTable = (table, ITERATIONS = 1) => {
const targetedCols = table.columns.filter(filterByType(Column));
const colNames = targetedCols.map((e) => e.name).join(',');
const vals = Array.from(Array(ITERATIONS).keys())
.map((idx) => targetedCols
.map((col) => createMockDataForColumn(col, table.primaryKey.includes(col), idx))
.filter(isNonNullable)
.join(','))
.join('\n');
return `${colNames}\n${vals}`;
};
export const createMockDataForMappingElementSource = (srcElement, editorStore) => {
if (srcElement instanceof Class) {
try {
return JSON.stringify(createMockDataForClass(srcElement), undefined, DEFAULT_TAB_SIZE);
}
catch (error) {
assertErrorThrown(error);
editorStore.applicationStore.notificationService.notifyWarning(`Can't generate test data for class '${srcElement}'. Error:\n${error.message}`);
return '';
}
}
else if (srcElement instanceof TableAlias &&
srcElement.relation instanceof Table) {
return createMockDataForTable(srcElement.relation);
}
else if (srcElement instanceof Table) {
return createMockDataForTable(srcElement);
}
editorStore.applicationStore.notificationService.notifyWarning(new UnsupportedOperationError(`Can't generate test data for mapping source`, srcElement));
return '';
};
//# sourceMappingURL=MockDataUtils.js.map