IntentArchitect / Support

A repository dedicated to handling issues and support queries
3 stars 0 forks source link

V4 Designer Error when accessing Domain from Services #33

Closed leonAtRain closed 1 year ago

leonAtRain commented 1 year ago

What happened?

We have a script that checks the service, find any attribute that ends with either From or To and replaces it with the first part of the attribute name, and changes the type to be of "TimePeriod" - which has a from and to. Then removes the redundant attributes. The script was working fine in the previous Intent Designer, but with v4 we're getting a new errror. Here is our existing script:

`var dtos = lookupTypesOf("Dto") var classes = lookupTypesOf("Class") dtos.forEach(function (dto) {

var timePeriodFields = dto.getChildren("DTO-Field").filter(x => x.typeReference.getType().getName() == "TimePeriod")

timePeriodFields.forEach(function (timePeriodField) {
    classes.forEach(function (_class) {
        if (dto.getName().startsWith(_class.getName())) {
            var attributes = _class.getChildren("Attribute")
            var timePeriodFrom = attributes.filter(x => x.getName() == timePeriodField.getName() + "From")[0]
            if (!timePeriodFrom) {
                timePeriodFrom = createElement("Attribute", timePeriodField.getName() + "From", _class.id)
            }
            timePeriodFrom.typeReference.setType("f1ba4df3-a5bc-427e-a591-4f6029f89bd7")
            timePeriodFrom.typeReference.setIsNullable(true)
            var timePeriodTo = attributes.filter(x => x.getName() == timePeriodField.getName() + "To")[0]
            if (!timePeriodTo) {
                timePeriodTo = createElement("Attribute", timePeriodField.getName() + "To", _class.id)
            }
            timePeriodTo.typeReference.setType("f1ba4df3-a5bc-427e-a591-4f6029f89bd7")
            timePeriodTo.typeReference.setIsNullable(true)
            var validFor = attributes.filter(x => x.getName().toLowerCase() == timePeriodField.getName())[0]
            if (validFor) {
                validFor.delete()
            }
        }
    })
})

})`

and the error that we see is this when executing: Error: Cannot mutate typeReference in a package reference. at Object.setType (file:///C:/Program%20Files/Intent%20Architect%20v4/resources/app.asar/wwwroot/js/app.min.js:1:2953052) at evalmachine.<anonymous>:15:46 at Array.forEach (<anonymous>) at evalmachine.<anonymous>:8:17 at Array.forEach (<anonymous>) at evalmachine.<anonymous>:7:22 at Array.forEach (<anonymous>) at evalmachine.<anonymous>:3:6

What version of Intent Architect are you using?

4

Additional information

No response

dandrejvv commented 1 year ago

Hi @leonAtRain , thank you for raising this. This does appear to be an intentional guard added in v4 to avoid certain kinds of issues which can now arise.

We'll be discussing your use case on our side to come up with possible solutions to your script, just so we understand your situation as well as possible, is it just for convenience that we have the changes happen from the services designer, or is there another reason you're doing so?

leonAtRain commented 1 year ago

There might be a better solution - but, the aim is to store the validFrom and validTo dates in the database as 2 separate fields, each of type OffsetDateTime. We define this in the Domain side by using 2 attributes - which relates to 2 columns in the database. But, the specification that we work with, require the format in json as : { "valid" : { "from" : "2023-01-01", "to" : "2030-01-01" } } as an example - in order to make this "easier" we scripted the validation that our DTO has been defined correctly - ie, using the "TimePeriod" Dto and only have one attribute in the Dto, We also made changes to the mapper classes to accommodate for this change. The problem comes in when one remaps a Dto to the Domain class- then the from and to fields both appear again, and need to be removed, using the script is a quick win for us. as we have this in almost every second Dto.

leonAtRain commented 1 year ago

Just as an update to this issue - after Good voice call, and explanation why the requirement for scripts not to be able to access the Domain Attributes from the Service designer, I do agree with this limitation (if one could call it that). So I've changed my code to accommodate, having 2 scripts that run in each designer. Also due to the fact that I know this might come in handy for other people, I've decided to share my results after the call I've had.

Just as a summary of what the code does - there is 2 Attributes in Domain which I want to "map" to 1 field in Service Dto. The Attribute's name end with "From" and "To" and I'm referencing the TimePeriod Dto which has "FromDate" and "ToDate" as dto-fields. The Script then also removes the "...From" and "...To" fields from the Service Dto and replace it with only the "..." part with the Type of TimePeriod. Then the last part of the script also fixes mappings that have been removed, so it finds the same field in the Domain as defined in the Dto, and maps those - obviously this does not cater for all mapping issues, but it would solve 95% of my problems I have currently.

` var dtos = lookupTypesOf("DTO") var classes = lookupTypesOf("Class") var timePeriod = dtos.filter(x => x.getName() == "TimePeriod")[0] if (timePeriod) { var timePeriodId = timePeriod.id

dtos.forEach(function (dto) {
    var entity = classes.filter(x => dto.getName().startsWith(x.getName()))[0]
    if (!entity) return
    var targetFrom = entity.getChildren("Attribute").filter(x => x.getName().endsWith("From"))[0]
    var targetTo =entity.getChildren("Attribute").filter(x => x.getName().endsWith("To"))[0]
    if (targetFrom && targetTo) {
        var timePeriodFields = dto.getChildren("DTO-Field").filter(x => x.getName().startsWith(targetFrom.getName().replace("From","")) && x.typeReference.getType().getName() == "TimePeriod")
        if (timePeriodFields.length == 0) {
            var timePeriod = createElement("DTO-Field", targetFrom.getName().replace("From",""), dto.id)
            timePeriod.typeReference.setType(timePeriodId)
        }
        dto.getChildren("DTO-Field").filter(x => x.getName() == targetFrom.getName()).forEach(x => x.delete())
        dto.getChildren("DTO-Field").filter(x => x.getName() == targetTo.getName()).forEach(x => x.delete())
    }
    entity.getChildren("Attribute").forEach(attrib => {
        dto.getChildren("DTO-Field").filter(field => attrib.getName() == field.getName()).forEach(matchField => {
            matchField.setMapping(attrib.id)
        })
    })
    entity.getAssociations("Generalization").forEach(association => {
        var base = association.typeReference.getType()
        base.getChildren("Attribute").forEach(attrib => {
            dto.getChildren("DTO-Field").filter(field => attrib.getName() == field.getName()).forEach(matchField => {
                matchField.setMapping([association.id, attrib.id])
            })
        })
    })
})

}`