1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | 'use strict';
|
16 |
|
17 | const ClassDeclaration = require('../introspect/classdeclaration');
|
18 | const EnumDeclaration = require('../introspect/enumdeclaration');
|
19 | const Field = require('../introspect/field');
|
20 | const ModelUtil = require('../modelutil');
|
21 | const RelationshipDeclaration = require('../introspect/relationshipdeclaration');
|
22 | const Util = require('../util');
|
23 | const Globalize = require('../globalize');
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | class InstanceGenerator {
|
34 |
|
35 | |
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | visit(thing, parameters) {
|
43 | if (thing instanceof ClassDeclaration) {
|
44 | return this.visitClassDeclaration(thing, parameters);
|
45 | } else if (thing instanceof RelationshipDeclaration) {
|
46 | return this.visitRelationshipDeclaration(thing, parameters);
|
47 | } else if (thing instanceof Field) {
|
48 | return this.visitField(thing, parameters);
|
49 | } else {
|
50 | throw new Error('Unrecognised ' + JSON.stringify(thing) );
|
51 | }
|
52 | }
|
53 |
|
54 | |
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | visitClassDeclaration(classDeclaration, parameters) {
|
62 | const obj = parameters.stack.pop();
|
63 | const properties = classDeclaration.getProperties();
|
64 | for (const property of properties) {
|
65 | if (!parameters.includeOptionalFields && property.isOptional()) {
|
66 | continue;
|
67 | }
|
68 | const value = obj[property.getName()];
|
69 | if(Util.isNull(value)) {
|
70 | obj[property.getName()] = property.accept(this,parameters);
|
71 | }
|
72 | }
|
73 | return obj;
|
74 | }
|
75 |
|
76 | |
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | visitField(field, parameters) {
|
84 | if(!field.isPrimitive()){
|
85 | let type = field.getFullyQualifiedTypeName();
|
86 | let classDeclaration = parameters.modelManager.getType(type);
|
87 | classDeclaration = this.findConcreteSubclass(classDeclaration);
|
88 | let fqn = classDeclaration.getFullyQualifiedName();
|
89 |
|
90 | if (parameters.seen.includes(fqn)){
|
91 | if (field.isArray()) {
|
92 | return [];
|
93 | }
|
94 | if (field.isOptional()) {
|
95 | return null;
|
96 | }
|
97 | throw new Error('Model is recursive.');
|
98 | }
|
99 | parameters.seen.push(fqn);
|
100 | } else { parameters.seen.push('Primitve');
|
101 | }
|
102 | let result;
|
103 | if (field.isArray()) {
|
104 | const valueSupplier = () => this.getFieldValue(field, parameters);
|
105 | result = parameters.valueGenerator.getArray(valueSupplier);
|
106 | } else {
|
107 | result = this.getFieldValue(field, parameters);
|
108 | }
|
109 | parameters.seen.pop();
|
110 | return result;
|
111 | }
|
112 |
|
113 |
|
114 | |
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | getFieldValue(field, parameters) {
|
121 | let type = field.getFullyQualifiedTypeName();
|
122 |
|
123 | if (ModelUtil.isPrimitiveType(type)) {
|
124 | switch(type) {
|
125 | case 'DateTime':
|
126 | return parameters.valueGenerator.getDateTime();
|
127 | case 'Integer':
|
128 | return parameters.valueGenerator.getInteger();
|
129 | case 'Long':
|
130 | return parameters.valueGenerator.getLong();
|
131 | case 'Double':
|
132 | return parameters.valueGenerator.getDouble();
|
133 | case 'Boolean':
|
134 | return parameters.valueGenerator.getBoolean();
|
135 | default:
|
136 | return parameters.valueGenerator.getString();
|
137 | }
|
138 | }
|
139 |
|
140 | let classDeclaration = parameters.modelManager.getType(type);
|
141 |
|
142 | if (classDeclaration instanceof EnumDeclaration) {
|
143 | let enumValues = classDeclaration.getOwnProperties();
|
144 | return parameters.valueGenerator.getEnum(enumValues).getName();
|
145 | }
|
146 |
|
147 | classDeclaration = this.findConcreteSubclass(classDeclaration);
|
148 |
|
149 | if (classDeclaration.isConcept()) {
|
150 | let concept = parameters.factory.newConcept(classDeclaration.getNamespace(), classDeclaration.getName());
|
151 | parameters.stack.push(concept);
|
152 | return classDeclaration.accept(this, parameters);
|
153 | } else {
|
154 | const id = this.generateRandomId(classDeclaration);
|
155 | let resource = parameters.factory.newResource(classDeclaration.getNamespace(), classDeclaration.getName(), id);
|
156 | parameters.stack.push(resource);
|
157 | return classDeclaration.accept(this, parameters);
|
158 | }
|
159 | }
|
160 |
|
161 | |
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 | findConcreteSubclass(declaration) {
|
172 | if (!declaration.isAbstract()) {
|
173 | return declaration;
|
174 | }
|
175 |
|
176 | const concreteSubclasses = declaration.getAssignableClassDeclarations()
|
177 | .filter(subclass => !subclass.isAbstract())
|
178 | .filter(subclass => !subclass.isSystemType());
|
179 |
|
180 | if (concreteSubclasses.length === 0) {
|
181 | const formatter = Globalize.messageFormatter('instancegenerator-newinstance-noconcreteclass');
|
182 | throw new Error(formatter({ type: declaration.getFullyQualifiedName() }));
|
183 | }
|
184 |
|
185 | return concreteSubclasses[0];
|
186 | }
|
187 |
|
188 |
|
189 |
|
190 | |
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | visitRelationshipDeclaration(relationshipDeclaration, parameters) {
|
198 | let classDeclaration = parameters.modelManager.getType(relationshipDeclaration.getFullyQualifiedTypeName());
|
199 | classDeclaration = this.findConcreteSubclass(classDeclaration);
|
200 | const factory = parameters.factory;
|
201 | const valueSupplier = () => {
|
202 | const id = this.generateRandomId(classDeclaration);
|
203 | return factory.newRelationship(classDeclaration.getNamespace(), classDeclaration.getName(), id);
|
204 | };
|
205 | if (relationshipDeclaration.isArray()) {
|
206 | return parameters.valueGenerator.getArray(valueSupplier);
|
207 | } else {
|
208 | return valueSupplier();
|
209 | }
|
210 | }
|
211 |
|
212 | |
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 | generateRandomId(classDeclaration) {
|
219 | let id = Math.round(Math.random() * 9999).toString();
|
220 | id = id.padStart(4, '0');
|
221 | return id;
|
222 | }
|
223 |
|
224 | }
|
225 |
|
226 | module.exports = InstanceGenerator;
|