/* * 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. */ 'use strict'; const ClassDeclaration = require('../introspect/classdeclaration'); const EnumDeclaration = require('../introspect/enumdeclaration'); const Field = require('../introspect/field'); const leftPad = require('left-pad'); const ModelUtil = require('../modelutil'); const RelationshipDeclaration = require('../introspect/relationshipdeclaration'); const randomWords = require('random-words'); const Util = require('../util'); /** * Generate sample instance data for the specified class declaration * and resource instance. The specified resource instance will be * updated with either default values or generated sample data. * @private * @class * @memberof module:composer-common */ class InstanceGenerator { /** * Visitor design pattern * @param {Object} thing - the object being visited * @param {Object} parameters - the parameter * @return {Object} the result of visiting or null * @private */ visit(thing, parameters) { if (thing instanceof ClassDeclaration) { return this.visitClassDeclaration(thing, parameters); } else if (thing instanceof RelationshipDeclaration) { return this.visitRelationshipDeclaration(thing, parameters); } else if (thing instanceof Field) { return this.visitField(thing, parameters); } else { throw new Error('Unrecognised ' + JSON.stringify(thing) ); } } /** * Visitor design pattern * @param {ClassDeclaration} classDeclaration - the object being visited * @param {Object} parameters - the parameter * @return {Object} the result of visiting or null * @private */ visitClassDeclaration(classDeclaration, parameters) { const obj = parameters.stack.pop(); const properties = classDeclaration.getProperties(); for(let n=0; n < properties.length; n++) { const property = properties[n]; const value = obj[property.getName()]; if(Util.isNull(value)) { obj[property.getName()] = property.accept(this,parameters); } } return obj; } /** * Visitor design pattern * @param {Field} field - the object being visited * @param {Object} parameters - the parameter * @return {Object} the result of visiting or null * @private */ visitField(field, parameters) { if (field.isArray()) { let result = []; for (let i = 0; i < 3; i++) { result.push(this.getSampleValue(field, parameters)); } return result; } else { return this.getSampleValue(field, parameters); } } /** * Get a sample value for the specified field. * @param {Field} field - the object being visited * @param {Object} parameters - the parameter * @return {*} A sample value for the specified field. */ getSampleValue(field, parameters) { let type = field.getFullyQualifiedTypeName(); if (ModelUtil.isPrimitiveType(type)) { switch(type) { case 'DateTime': return new Date(Math.random() * Date.now()); case 'Integer': return Math.round(Math.random() * Math.pow(2, 16)); case 'Long': return Math.round(Math.random() * Math.pow(2, 32)); case 'Double': return Number((Math.random() * Math.pow(2, 8)).toFixed(3)); case 'Boolean': return Math.round(Math.random()) === 1; default: return randomWords({min: 1, max: 5}).join(' '); } } let classDeclaration = parameters.modelManager.getType(type); if (classDeclaration instanceof EnumDeclaration) { let enumValues = classDeclaration.getOwnProperties(); return enumValues[Math.floor(Math.random() * enumValues.length)].getName(); } else { let identifierFieldName = classDeclaration.getIdentifierFieldName(); let idx = Math.round(Math.random() * 9999).toString(); idx = leftPad(idx, 4, '0'); let id = `${identifierFieldName}:${idx}`; let resource = parameters.factory.newResource(classDeclaration.getModelFile().getNamespace(), classDeclaration.getName(), id); parameters.stack.push(resource); return classDeclaration.accept(this, parameters); } } /** * Visitor design pattern * @param {RelationshipDeclaration} relationshipDeclaration - the object being visited * @param {Object} parameters - the parameter * @return {Object} the result of visiting or null * @private */ visitRelationshipDeclaration(relationshipDeclaration, parameters) { let classDeclaration = parameters.modelManager.getType(relationshipDeclaration.getFullyQualifiedTypeName()); let identifierFieldName = classDeclaration.getIdentifierFieldName(); let factory = parameters.factory; if (relationshipDeclaration.isArray()) { let result = []; for (let i = 0; i < 3; i++) { let idx = Math.round(Math.random() * 9999).toString(); idx = leftPad(idx, 4, '0'); let id = `${identifierFieldName}:${idx}`; let relationship = factory.newRelationship(classDeclaration.getModelFile().getNamespace(), classDeclaration.getName(), id); result.push(relationship); } return result; } else { let idx = Math.round(Math.random() * 9999).toString(); idx = leftPad(idx, 4, '0'); let id = `${identifierFieldName}:${idx}`; let relationship = factory.newRelationship(classDeclaration.getModelFile().getNamespace(), classDeclaration.getName(), id); return relationship; } } } module.exports = InstanceGenerator;