Generate an SDK Script Based on an Existing Model

Last modified: April 18, 2024

1 Introduction

To help you to find out how you can write code to alter your model, the SDK ships with a nice reverse engineering tool. Given a fully loaded model unit, you can generate the JavaScript code that would create that very same unit using code. This way, you can build a template model in Studio Pro, then generate the code you would need to write to achieve the same.

2 For the Impatient

To generate the code for a fully-loaded unit you can use the following code:

1
2
3
import { JavaScriptSerializer } from "mendixmodelsdk";

console.log(JavaScriptSerializer.serializeToJs(someFullyLoadedModelUnit));

3 Example

Let’s say you want to generate a set of entities in a domain model that looks like this:

First you need to create the two entities in the domain model and commit that to Team Server. Next, you need to write a script like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { JavaScriptSerializer } from "mendixmodelsdk";
import { MendixPlatformClient } from "mendixplatformsdk";

const projectId = "{YOUR_PROJECT_ID}";
const moduleName = "MyFirstModule";

async function main() {
    const client = new MendixPlatformClient();

    const app = client.getApp(projectId);

    const workingCopy = await app.createTemporaryWorkingCopy("main"); // Use 'trunk' for Subversion based apps
    const model = await workingCopy.openModel();

    const domainModelInterface = model.allDomainModels().filter(dm => dm.containerAsModule.name === moduleName)[0];
    const domainModel = await domainModelInterface.load();

    console.log(JavaScriptSerializer.serializeToJs(domainModel));
}

main().catch(console.error);

When you execute the script, you will get the following output of your console. You can also pipe the output to a file if the model is more complex:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
(function (unit, model) {

	/*
	 * JavaScript code generated by mendixmodelsdk.sdk.extras.JavaScriptSerializer
	 * from unit with id "{PROJECT_ID}" of type DomainModels$DomainModel
	 * in working copy "{PROJECT_NAME}"
	 * on {DATE}.
	 */

	var noGeneralization1 = domainmodels.NoGeneralization.create(model);

	var stringAttributeType1 = domainmodels.StringAttributeType.create(model);

	var storedValue1 = domainmodels.StoredValue.create(model);

	var address1 = domainmodels.Attribute.create(model);
	address1.name = "Address";
	address1.type = stringAttributeType1;   // Note: for this property a default value is defined.
	address1.value = storedValue1;   // Note: for this property a default value is defined.

	var stringAttributeType2 = domainmodels.StringAttributeType.create(model);

	var storedValue2 = domainmodels.StoredValue.create(model);

	var phone1 = domainmodels.Attribute.create(model);
	phone1.name = "Phone";
	phone1.type = stringAttributeType2;   // Note: for this property a default value is defined.
	phone1.value = storedValue2;   // Note: for this property a default value is defined.

	var person1 = domainmodels.Entity.create(model);
	person1.name = "Person";
	person1.location = {"x":150,"y":270};
	person1.generalization = noGeneralization1;   // Note: for this property a default value is defined.
	person1.attributes.push(address1);
	person1.attributes.push(phone1);
	person1.imageData = "";

	var noGeneralization2 = domainmodels.NoGeneralization.create(model);

	var stringAttributeType3 = domainmodels.StringAttributeType.create(model);

	var storedValue3 = domainmodels.StoredValue.create(model);

	var roleName1 = domainmodels.Attribute.create(model);
	roleName1.name = "RoleName";
	roleName1.type = stringAttributeType3;   // Note: for this property a default value is defined.
	roleName1.value = storedValue3;   // Note: for this property a default value is defined.

	var role1 = domainmodels.Entity.create(model);
	role1.name = "Role";
	role1.location = {"x":340,"y":580};
	role1.generalization = noGeneralization2;   // Note: for this property a default value is defined.
	role1.attributes.push(roleName1);
	role1.imageData = "";

	var associationDeleteBehavior1 = domainmodels.AssociationDeleteBehavior.create(model);

	var person_Role1 = domainmodels.Association.create(model);
	person_Role1.name = "Person_Role";
	person_Role1.deleteBehavior = associationDeleteBehavior1;   // Note: for this property a default value is defined.
	person_Role1.parentConnection = {"x":75,"y":100};
	person_Role1.childConnection = {"x":30,"y":0};

	var domainModel1 = domainmodels.DomainModel.createIn(unit);
	domainModel1.entities.push(person1);
	domainModel1.entities.push(role1);
	domainModel1.associations.push(person_Role1);

	person_Role1.parent = person1;
	person_Role1.child = role1;

})

If you want to re-create the entities of an existing domain model, you will need to alter the script a little bit. Replace the first line with:

1
function generate(domainModel1: domainmodels.DomainModel, model: IModel) {

The original code expects a unit as the first argument. The unit is supposed to be the container for the domain model. However, you don’t want to create a new domain model, you are going to re-use an existing domain model instead. Therefore, you need to remove this line:

1
const domainModel1 = domainmodels.DomainModel.createIn(unit);

Remove the last bracket on the last line so your JavaScript code will look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function generate(domainModel1: domainmodels.DomainModel, model: IModel) {
    /*
     * JavaScript code generated by mendixmodelsdk.sdk.extras.JavaScriptSerializer
     * from unit with id "{PROJECT_ID}" of type DomainModels$DomainModel
     * in working copy "{PROJECT_NAME}"
     * on {DATE}.
     */

    var noGeneralization1 = domainmodels.NoGeneralization.create(model);
.
.
.
.
.
.
    person_Role1.parentConnection = { x: 75, y: 100 };
    person_Role1.childConnection = { x: 30, y: 0 };

    domainModel1.entities.push(person1);
    domainModel1.entities.push(role1);
    domainModel1.associations.push(person_Role1);

    person_Role1.parent = person1;
    person_Role1.child = role1;
}

For the next step, you will create a script that make use of the function. The script is written in TypeScript, so it will be able to run a JavaScript code just fine. This script will create a blank app and modify the domain model in the MyFirstModule module.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { domainmodels, IModel } from "mendixmodelsdk";
import { MendixPlatformClient } from "mendixplatformsdk";

async function main() {
    const client = new MendixPlatformClient();

    const app = await client.createNewApp(`NewApp-${Date.now()}`, {
        repositoryType: "git"
    });

    const workingCopy = await app.createTemporaryWorkingCopy("main");
    const model = await workingCopy.openModel();

    const domainModelInterface = model.allDomainModels().filter(dm => dm.containerAsModule.name === "MyFirstModule")[0];
    const domainModel = await domainModelInterface.load();

    generate(domainModel, model);

    await model.flushChanges();

    await workingCopy.commitToRepository("main");
}

main().catch(console.error);

//The generated code
function generate(domainModel1: domainmodels.DomainModel, model: IModel) {
.
.
.
}

Execute the script. You should have a new app with the generated entities.