新しい投稿

Rechercher

記事
· 2024年7月16日 2m read

Configuração de VSCode Auto Save e ObjectScript CompileOnSave

Olá!

Recentemente estive investigando uma situação incômoda enquanto editava classes ou rotinas ObjectScript no VSCode. O que acontecia era que, como estava escrevendo as linhas de código na minha classe (por exemplo: a adição de um novo método, mudança da assinatura de classe ou de um bloco de código) isso ocasionava uma rápida revisão da sintaxe, reformatação e compilação - e inevitavelmente (já que eu estava apenas na metade da escrita), isso gerava erros de compilação.

Sabendo que estava a meio caminho de adicionar código, podia simplesmente descartar essa mensagem, mas isso começou a ficar incômodo e me condicionou a ignorar possíveis erros (o que não é bom).

Ainda pior, o processo de compilação também reformatava o documento e às vezes rompia o que antes eram linhas de código bem formatadas (que apareciam abaixo da linha que eu estava escrevendo, o que me obrigava a ir até essa zona do documento e arrumá-las novamente.

O que é isso que acontece?

Há duas configurações em jogo:

  1. A configuração de salvar automaticamente do VSCode (files.autosave), que dita se deve salvar automaticamente um documento que tenha sido modificado e, se sim, quanto tempo esperar antes de salvar (files.autoSaveDelay)
  2. CompileOnSave da extensão ObjectScript (objectscript.compileOnSave), que determina se depois de salvar o documento, ele também se importa e compila no namespace conectado do IRIS.

Como eu tinha o autosave ativado, e com um retardo de espera pequeno, junto com o compileOnSave, significava que o código parcialmente editada se seguia compilando, gerando os erros aos quais me referi, e como mencionado, às vezes reformatando blocos de códigos bons pré-existentes.

No meu caso, decidi pelo seguinte:

  1. Autosalvar (files.autosave) desativado (se ignora autosaveDelay), e...
  2. CompileOnSave (objectscript.compileOnSave) ativado.

Agora, quando estou satisfeito com minhas edições (e quando eu queira!), aperto Ctrl+S para salvar, importar e compilar minha classe, e estou atento a essa mensagem emergente que agora tem verdadeiro significado e propósito.

Você pode escolher uma combinação diferente (por exemplo, seguir em frente e salvar automaticamente depois de 5 minutos mais ou menos, aceitando que o código pode não compilar completamente). No entanto, decidi que a combinação anterior funciona para mim, e espero que - se você está passando pelo mesmo incômodo, esse artigo possa ajudá-lo a encontrar sua configuração ótima.

Agradeço a @Patrick Sulin, e @Raj Singh por me indicar como chegar a estes ajustes!

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください
質問
· 2024年7月16日

How to resync ^ROUTINE and ^rINDEX?

I have a few routines in ^rINDEX that are missing in ^ROUTINE. At least some of those routines lack a timestamp, probably Date and Time Modified in ^rINDEX. It causes D %RO crash when such a routine is referenced by a routine range, since "" is an illegal $ZDTH value.

Healthy entry (note the timestamp): ^rINDEX("ABC,"INT")    =    $lb("2021-06-15 15:08:38.846885",)   ;The second argument is sometimes present and sometimes not, likely the routine size.

Unhealthy entry (note an empty timestamp): ^rINDEX("DEF,"INT")    =    $lb("",21) 

Finally, a question, not only for this situation. Is there an official, or a recommended way to rebuild rINDEX, maybe ^ROUTINE too. rINDEX has quite a few various purpose nodes, so it's probably not as straightforward as creating or deleting its nodes above based on ^ROUTINE entries.

3 Comments
ディスカッション (3)2
続けるにはログインするか新規登録を行ってください
記事
· 2024年7月16日 6m read

Method or Class Method?

For programmers new to ObjectScript, one question will inevitably arise: “What is the difference between methods and class methods?” A typical answer would be: “A class method applies to a class, but a method applies to an instance of that class.” While that answer is correct, it lacks important information on how these methods differ, and how they are used in ObjectScript. Many things could be written as either. For instance, suppose we had a class called “User.Person” with a property called “Name”. If we wanted to create a method to write that name, we could do either of the following:
 

Method WriteName()
{
    write ..Name
}
ClassMethod ClassWriteName(id)
{
    write ##class(User.Person).%OpenId(id).Name
}

In many cases, it does not matter what we choose. However, there are some compelling reasons why we might prefer one over the other. We will dive deeper into this topic today to find that out.

Methods: General Guidelines

Methods are sometimes referred to as instance methods for the sake of clarity. They are selected when the method does something to or with a specific instance. Methods are the tools to use when an in-memory instance of an object is required. This, of course, means that they should only be defined in object classes. Since they are operating on an instance, they can refer to that object’s properties using the double-dot syntax, as in the WriteName method above. One of the most basic examples we all quickly become familiar with is %Save(). If we do not have an instance of the object, it is impossible to know what to save.

Instance methods are also an excellent choice when a method must be able to operate on an instance of an object before that instance is saved (or inserted via SQL if the class extends %Persistent). %ValidateObject is a great example of this situation. We need to make sure the object is valid before we save it.

Class Methods: General Guidelines

Although class methods are defined within a class, they are not tied to a specific instance of a class. If you are familiar with some other programming languages, you may be accustomed to calling such methods “static methods”. Since these methods are not called on a specific instance of the class, you cannot employ the double-dot syntax to refer to properties of the class. You must get an instance of an object instead, and then use the dot syntax to refer to that instance’s properties.

Class methods must be used when a method does not have access to an instance. Methods that create a new instance of an object, a.k.a. “constructors”, in most cases, will be class methods. One situational exception to this is %ConstructClone. It builds a new instance of an object copied from an existing instance, so it is defined as an instance method. The default constructor for most objects is %New(), but you may also want to write some of your own.

Class methods are favored when a method operates on multiple instances of a class. We could transform such methods into instance methods, and make them work just fine, but doing it would not make much sense. For example, if we wanted to convert all of our names to uppercase, we could use the following method:

ClassMethod AllToUpper(){
    set stmt = ##class(%SQL.Statement).%New()
    set query = "SELECT ID FROM SQLUser.Person"
    do stmt.%Prepare(query)
    set result = stmt.%Execute()
    while result.%Next(){
        set myPerson = ##class(User.Person).%OpenId(result.GetData(1))
        set myPerson.Name = $ZCONVERT(myPerson.Name,"U")
        do myperson.%Save()
    }
}

If we defined this method as an instance method, it would still do the same thing. However, we do not usually do that because it would require us to take the extra step of either creating or opening an instance of the class before calling the method, which would be a waste of time and resources.

Likewise, class methods are picked when a method operates on no instances of an object. Suppose we have a class parameter defined, in this case, to override the caption parameter, do the following:

/// Optional name used by the <i>Form Wizard</i> for a class when generating forms.
Parameter CAPTION = "People";

Since parameters are shared among all members of a class (a “static variable” as called by some other programming languages), it is not necessary to access a specific instance of a class to refer to that parameter. If we wanted to write that parameter’s value, we could do it as shown below:

ClassMethod WriteCaption()
{
    write ..#CAPTION
}

Once again, in this case, we could convert it into an instance method. However, it would be just as inefficient as in our previous example.

Class Methods: Special Cases

So far, these all have been general programming guidelines, which, by the way, you could break and still get the desired result. However, there are a few specific cases when you must use a class method.

If you want to call a method in a trigger, it must be a class method. Triggers can be powerful, but they also have some extra rules and special syntax since they are executed when data is in flux. They allow you to specify whether you want to refer to the old value or the new value of a changing property, and that is precisely why they cannot use the double-dot syntax. Suppose I want to log the UTC timestamp of a record being deleted from my Person. I could define the following method and trigger to accomplish that as indicated below:

ClassMethod LogDelete(id)
{
    set ^LogDelete("Person",id) = $ZDATETIME($ZTIMESTAMP)
}

Trigger LogDelete [ Event = DELETE, Foreach = row/object ]
{
    do ##class(User.Person).LogDelete({%%ID})
}

Then, when I delete a record from that table, I will see a global set like the following one:

If we want a method to be exposed as an SQL procedure, it must be a class method. If my name field is just a first and last names separated by a space, “David Hockenbroch,” but we want to have a stored procedure to return it in the way favored by Elon Musk when it comes to his phone order, “Hockenbroch, David,” we can write a simple function like the one below:

ClassMethod AlphaName(id) As %String [ SqlProc ]
{
    set myPerson = ##class(User.Person).%OpenId(id)
    return $P(myPerson.Name," ",2)_", "_$P(myPerson.Name," ",1)
}

Note the SqlProc keyword in the function definition. This keyword will tell the compiler to project this method as an SQL procedure called Person_AlphaName. We can then exploit it in a query as follows:

select name, person_alphaname(id) As "AlphaName" from person

We will see the next result:

Finally, I can utilize a class method to define how an SQL computed property is calculated. Suppose I have the following property in my class:

Property AlphaName As %String [ SqlComputed ];

When we employ the SqlComputed keyword, we must define the computation to be operated. One way to do that is with the SqlComputeCode keyword. The other one is to specify a class method that returns the desired value. This method must have the same name as its property followed by “Computation.” Consider the following example:

ClassMethod AlphaNameComputation(cols As %PropertyHelper) As %String
{
    return $P(cols.getfield("Name")," ",2)_", "_$P(cols.getfield("Name")," ",1)
}

If we do that, then the property will be calculated any time the object is inserted or updated. Note the %PropertyHelper argument that gets passed to this method. This object allows you to access the properties of the individual instance whose property is being calculated despite this being a class method. You can use the getfield property of that object and give it a property name to get that property. In this case, we just have a column, so we should use the SQL:

select Name, AlphaName from person

The result you get then will be identical to the one before:

In Conclusion

I hope this review of methods was detailed enough and included everything you need to know to determine which kind of method to use. If I have missed anything, please, let me know in the comments below!

2 Comments
ディスカッション (2)3
続けるにはログインするか新規登録を行ってください
お知らせ
· 2024年7月16日

[Video] Usando Inteligência Artificial/Aprendizado de Máquina para Avaliação da Dor em um Ambiente Clínico

Olá Comunidade,

Assista a este vídeo para saber mais sobre a tecnologia de inteligência artificial PainChek, que avalia a dor do paciente na cabeceira do hospital, aproveita a interoperabilidade do InterSystems IRIS para se conectar a sistemas de registros médicos eletrônicos de terceiros:

⏯ Usando Inteligência Artificial/Aprendizado de Máquina para Avaliação da Dor em um Ambiente Clínico @ Global Summit 2023

Apresentadores:
🗣 Philip Daffas, CEO and Managing Director, PainChek
🗣 James Matthias, Head of Product - Adult, Enterprise

Inscreva-se no nosso canal do YouTube InterSystems Developers para receber notificações sobre novos vídeos!

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください
お知らせ
· 2024年7月16日

[Video] Encryption Landscape for Data at Rest

Hey Developers,

Watch this video to discover an analytical approach to InterSystems IRIS encryption and how it interacts with storage compression and deduplication compared with storage-level encryption:

⏯ Encryption Landscape for Data at Rest @ Global Summit 2023

🗣  Presenter: @Can (Jon) Gencler, Technical Specialist, InterSystems

Subscribe to our YouTube channel InterSystems Developers to stay up to date!

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください