Vitaliy Serdtsev · May 10, 2018 go to post

Localization in Caché DBMS

Simple example:

  1. Class dc.test Extends %ZEN.Component.page
    {
    
    Parameter DOMAIN = "DCTEST";
    
    XData Contents [ XMLNamespace "http://www.intersystems.com/zen" ]
    {
    <page xmlns="http://www.intersystems.com/zen">
      <radioSet id="lng"
        label="Текущий язык"
        layout="vertical"
        displayList="Португальский,Русский"
        valueList="pt-br,ru"
        value="ru"
        onchange="zenPage.changeLang(zenThis.value);"
      />
      <form>
        <text label="Описание" required="true" requiredMessage="обязательно." />
        <submit caption="Сохранить"/>
      </form>
    </page>
    }
    
    /// User clicked to change preferred language.
    ClientMethod changeLang(lng) [ Language = javascript ]
    {
      var ok this.SrvChangeLang(lng);
      self.document.location.reload();
    }
    
    /// Change preferred language for this session and page
    ClassMethod SrvChangeLang(lngAs %Boolean ZenMethod ]
    {
      %session.Language=lng
      %response.Language=lng
      q $$$YES
    }
    
    Method %OnAfterCreatePage() As %Status
    {
      ..%SetValueById("lng",%session.Language)
      Quit $$$OK
    }
    
    }
  2. USER>##class(%MessageDictionary).ExportDomainList("messages_ru.xml","DCTEST","ru")
    
    Result (messages_ru.xml):
    
    <?xml version="1.0" encoding="UTF-8"?>
    <MsgFile Language="ru">
       <MsgDomain Domain="DCTEST">
          <Message Id="358179803">Текущий язык</Message>
          <Message Id="1805419696">Португальский,Русский</Message>
          <Message Id="2153752096">Описание</Message>
          <Message Id="2835101332">обязательно.</Message>
          <Message Id="3683485237">Сохранить</Message>
       </MsgDomain>
    </MsgFile>
    
  3. messages_pt-br.xml:
    
    <?xml version="1.0" encoding="UTF-8"?>
    <MsgFile Language="pt-br">
       <MsgDomain Domain="DCTEST">
          <Message Id="358179803">Idioma atual</Message>
          <Message Id="1805419696">Português,Russo</Message>
          <Message Id="2153752096">Descrição</Message>
          <Message Id="2835101332">é obrigatório.</Message>
          <Message Id="3683485237">Salvar</Message>
       </MsgDomain>
    </MsgFile>
    
    USER>##class(%MessageDictionary).Import("messages_pt-br.xml")
  4. Profit!
Vitaliy Serdtsev · May 7, 2018 go to post
USER>w $zv
Cache for Windows (x86-32) 2015.2 (Build 664_3U) Wed Aug 12 2015 12:29:34 EDT

The date is saved to the database correctly.

Class dc.A Extends %Persistent
{
Property DOB As %Date;
}

Class dc.MVC.A Extends %ZEN.DataModel.ObjectDataModel
{

Property DOB As %Date(ZENATTRS "id:DOB|format:DMY|separator:/"ZENCONTROL "dateText");

Method %OnNewSource(Output pSC As %Status = {$$$OK}) As %RegisteredObject
{
  ##class(dc.A).%New()
}

Method %OnOpenSource(
  pID As %String,
  pConcurrency As %Integer -1,
  Output pSC As %Status = {$$$OK}) As %RegisteredObject
{
  ##class(dc.A).%OpenId(pID,pConcurrency,.pSC)
}

Method %OnSaveSource(pSource As dc.AAs %Status
{
  pSource.%Save()
}

ClassMethod %OnDeleteSource(pID As %StringAs %Status
{
  ##class(dc.A).%DeleteId(pID)
}

Method %OnLoadModel(pSource As dc.AAs %Status
{
  ..DOB pSource.DOB
  q $$$OK
}

Method %OnStoreModel(pSource As dc.AAs %Status
{
  pSource.DOB = ..DOB
  q $$$OK
}

}

Class dc.test Extends %ZEN.Component.page
{

XData Contents [ XMLNamespace "http://www.intersystems.com/zen" ]
{
  <page xmlns="http://www.intersystems.com/zen">
    <dataController id="a-controller" modelClass="dc.MVC.A" modelId=""/>
    <dynaForm id="a-form"  controllerId="a-controller"/>
    <button caption="Save" onclick="zen('a-form').save();" />
  </page>
}

}
Vitaliy Serdtsev · Apr 25, 2018 go to post

Still can be so:

Class dc.test Abstract ]
{

ClassMethod Test("#")
{
  "Test_",s
}

ClassMethod mac() [ ProcedureBlock = 0 ]
{
sub1(s=1)
  "sub1_",s
  q
sub2(s=2)
  "sub2_",s
  q
procPrivate(s=3) {
  "procPrivate_",s
}
procPublic(s=3) public {
  "procPublic_",s
}
}

}

Result:

USER>zTest^dc.test.1(1)
Test_1
USER>sub1^dc.test.1
sub1_1
USER>sub2^dc.test.1
sub2_2
USER>sub1^dc.test.1(10)
sub1_10
USER>sub2^dc.test.1(10)
sub2_10
USER>procPrivate^dc.test.1(10)
 
D procPrivate^dc.test.1(10)
^

USER>procPublic^dc.test.1(10)
procPublic_10
USER>
Vitaliy Serdtsev · Apr 14, 2018 go to post

%PosixTime

%PosixTime is preferable to %TimeStamp, because it takes up less disk space and memory than the %TimeStamp data type and provides better performance than %TimeStamp.proof

Vitaliy Serdtsev · Apr 6, 2018 go to post

My best result is 77726967 so far.

Class ITPlanet.Task4 Abstract ]
{

ClassMethod main(As %Integer 10)
{
 x=1:1:y=1:1:w $c(y#s<2!$lf($lb(1,s,y,s-y+1),x)*3+32)
}

ClassMethod length(
  class = {$classname()},
  method "main"As %Integer CodeMode = expression ]
{
##class(%Dictionary.MethodDefinition).IDKEYOpen(classmethod).Implementation.Size
}

}

USER>##class(ITPlanet.Task4).length()
67
USER>##class(ITPlanet.Task4).main(11)

###########
##       ##
# #     # #
#  #   #  #
#   # #   #
#    #    #
#   # #   #
#  #   #  #
# #     # #
##       ##
###########
Vitaliy Serdtsev · Mar 27, 2018 go to post

Make two changes to your code:

  1. /// return json
    Method infoJson() As %String WebMethod ]
    {
        set soapresponse=##class(webservice.SOAPResponse).%New()
        set soapresponse.CustomerID="1"
        set soapresponse.Name="2"
        set soapresponse.Street="3"
        set soapresponse.City="4"
        set soapresponse.State="5"
        set soapresponse.Zip="6"
    
        set stream=##class(%Stream.TmpBinary).%New()
        do ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(stream,soapresponse,,,$$$YES,"s")
        quit stream.Read($$$MaxStringLength)
    }
  2. /// write ##class(PRD.Test).test1()
    ClassMethod test1() As %String
    {
        set soapresponse=##class(webservice.SOAPResponse).%New()
        set soapresponse.CustomerID="1"
        set soapresponse.Name="2"
        set soapresponse.Street="3"
        set soapresponse.City="4"
        set soapresponse.State="5"
        set soapresponse.Zip="6"
        
        set stream=##class(%Stream.TmpBinary).%New()
        do ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(stream,soapresponse,,,$$$YES,"s")
        quit stream.Read($$$MaxStringLength)
    }
Vitaliy Serdtsev · Mar 5, 2018 go to post

Fixed bugs/typos and added new types.

#include %PVA
types ; Show COS-Datatypes ; kav ; 2018-03-04
 array,i,bitstring
 
 s $bit(bitstring,1) = 1

 "№",?4,"VALUE",?30,"JSON",?45,"$LISTBUILD",!,$TR($J("",55)," ","-"),!
 
 array=[
          (bitstring),
          ($ZBITSET($ZBITSTR(4,1),2,0)),
          ($lb("")),
          null,
          true,
          false,
          (##class(%ZEN.proxyObject).%New()),
          [],
          {},
          "abcd",
          ($wc(35222)),
          "2",
          2,
          -2,
          2.1,
          -2.1,
          ($double(2.1))
          ]
 array."18"=2
 array."19"=-2
          
 i=0:1:array.%Size() {
   i,")",?4,array.%Get(i),?30,$$TypeOf1(.array,i),?45,$$TypeOf2(array.%Get(i)),!
 }
 
 // Return JSON datatype by the documented way
 //
TypeOf1(&array,key)
{
  typ=array.%GetTypeCodeOf(key)
  typ_" "_$case(typ,
    $$$PVVALUENULL:"null",
    $$$PVVALUETRUE:"boolTrue",
    $$$PVVALUEFALSE:"boolFalse",
    $$$PVVALUEINTEGERPOS:"+int",
    $$$PVVALUEINTEGERNEG:"-int",
    $$$PVVALUEUNUSED1:"unused",
    $$$PVVALUEARRAY:"array",
    $$$PVVALUEOBJECT:"object",
    $$$PVVALUETEXT:"text",
    $$$PVVALUENUMBER:"number",
    $$$PVVALUEOVERFLOW:"overflow",
    $$$PVVALUECACHENUMERIC:"cacheNumeric",
    $$$PVVALUEOREF:"oref",
    $$$PVVALUEUNASSIGNED:"unassigned",
    $$$PVVALUELONGPOS:"+long",
    $$$PVVALUELONGNEG:"-long",
    $$$PVVALUEBYTE:"byte[]",
    $$$PVVALUEDATETIME:"dateTime",
    $$$PVVALUEDOUBLE:"double",
    $$$PVVALUESINGLE:"single",
    $$$PVVALUEUTF8:"utf8",
    $$$PVVALUENESTED:"nested",
    $$$PVVALUEEOF:"eof",
    :"unknown")
}
   
 // Return datatype by the undocumented $LB() way
 //
TypeOf2(val)
 {
  i $l(val)>253 {
    typ=$ziswide(val)+1
  else {
    typ=$a($lb(val),2)
  }
  typ_" "_$case(typ
    ,1:"8bitString"
    ,2:"16bitString"
    ,4:"nonNegativeInteger"
    ,5:"negativeInteger"
    ,6:"nonNegativeFloat"
    ,7:"negativeFloat"
    ,8:"double"
    , :"??? never seen before")
}

Result:

USER>^types
№   VALUE                     JSON           $LISTBUILD
-------------------------------------------------------
0)  Ÿ                          8 text         1 8bitString
                              8 text         1 8bitString
2)                            8 text         1 8bitString
3)                            0 null         1 8bitString
4)  1                         1 boolTrue     1 8bitString
5)  0                         2 boolFalse    1 8bitString
6)  4@%ZEN.proxyObject        12 oref        1 8bitString
7)  2@%Library.DynamicArray   6 array        1 8bitString
8)  1@%Library.DynamicObject  7 object       1 8bitString
9)  abcd                      8 text         1 8bitString
10) 視                         8 text         2 16bitString
11) 2                         8 text         1 8bitString
12) 2                         9 number       4 nonNegativeInteger
13) -2                        9 number       5 negativeInteger
14) 2.1                       9 number       6 nonNegativeFloat
15) -2.1                      9 number       7 negativeFloat
16) 2.1000000000000000888     18 double      8 double
17)                           13 unassigned  1 8bitString
18) 2                         3 +int         4 nonNegativeInteger
19) -2                        4 -int         5 negativeInteger
20)                           31 eof         1 8bitString
Vitaliy Serdtsev · Mar 3, 2018 go to post

On my desktop quite other results.

  N,j,time

  N=1e8

  j=1,2/*,3,4,5*/ {
    j,") "

    time=$zh
    d @("j"_j)(N)
    w $zh-time," s.",!
  }
  q
j1(N) public {
  i=1:1:{(a,b,c,d,e,f)=0}
}
j2(N) public {
  i=1:1:{a=0,b=0,c=0,d=0,e=0,f=0}
}
j3(N) public {
  i=1:1:{a=0,b=1,c=2,d=3,e=4,f=5}
}
j4(N) public {
  i=1:1:{a=0 b=1 c=2 d=3 e=4 f=5}
}
j5(N) public {
  i=1:1:{s $lb(a,b,c,d,e,f)=$lb(0,1,2,3,4,5)}
}

Results:

USER>^perf
1) 11.814189 s.
2) 4.683832 s.

As you can see the difference is almost 2.5 times.

Vitaliy Serdtsev · Feb 2, 2018 go to post

Please note that the option with %INLIST does not yet use “collection” indexes, and will therefore be slower than the one provided above proof

Vitaliy Serdtsev · Dec 29, 2017 go to post

Undefined variable and the variable contains "" (null) is two different situations, e.g. (see $DATA):

kill myObj
write $data(myObj),! ; -> 0
set myObj=$$$NULLOREF
write $data(myObj),! ; -> 1

In your case it would be better to use $IsObject:

kill myObj
write $IsObject(myObj),! ; -> 0
set d=$$$NULLOREF
write $IsObject(myObj),! ; -> 0
set myObj={}
write $IsObject(myObj),! ; -> 1

Accordingly, should be do $$$AssertTrue('$IsObject(myObj), "myObj is null")

Vitaliy Serdtsev · Dec 29, 2017 go to post

You are right, the macro $$$NULL present only in %sqlMigration.inc and this is not the file that developers often include to its project.
I prefer to use the macro $$$NULLOREF/$$$NULLOID from %occExtent.inc, which is available by default in the class that inherits from %Library.Base, and for routines is enough to include %systemInclude.inc.

Vitaliy Serdtsev · Dec 28, 2017 go to post

Why so difficult?
This similarly following condition:

WHERE 
(
year(current_date) - year(DOB)
) >= 13

It Besides above was already indicated, why does not follow to use such a code, for example:

select datediff(year,
todate(to_char({'1990-12-31'},'YYYY')||':1','YYYY:MM'), -- birthday
todate(to_char({'2003-01-01'},'YYYY')||':1','YYYY:MM') -- report date
)

This gives an incorrect result - 13, although it should be 12.

Vitaliy Serdtsev · Dec 26, 2017 go to post

Here's another way (without PlaceAfter):

Class Macro.Child Extends Macro.Parent
{

ClassMethod %inc() [ InternalPrivate ]
{
  #include Child
}

ClassMethod Test()
{
  write "Class: " $classname() , ! , "Value: " $$$name
}

}
Vitaliy Serdtsev · Dec 26, 2017 go to post

The key difference of $classmethod is runtime:

$CLASSMETHOD permits a ObjectScript program to invoke an arbitrary class method in an arbitrary class. Both the class name and the method name may be computed at runtime or supplied as string constants.proof

Vitaliy Serdtsev · Dec 26, 2017 go to post

Class include is not required (and does not seem to affect anything) and can be omitted
Yeah, I just forgot to delete that line.

Vitaliy Serdtsev · Dec 26, 2017 go to post

Then this:

Include Child

Class Macro.Child Extends Macro.Parent
{

ClassMethod first()
{
  #include Child
}

ClassMethod Test() [ PlaceAfter = first ]
{
  write "Class: " $classname() , ! , "Value: " $$$name
}

}

or this:

ClassMethod Test()
{
  #include Child
  write "Class: " $classname() , ! , "Value: " $$$name
}
Vitaliy Serdtsev · Dec 26, 2017 go to post

Macro.Parent.cls:

Include Parent

Class Macro.Parent
{

ClassMethod Test()
{
  write "Class: " $classname() , ! , "Value: " $$$name 
}

}

Macro.Child.cls:

Include Child

Class Macro.Child Extends Macro.Parent
{

ClassMethod Test()
{
  write "Class: " $classname() , ! , "Value: " $$$name 
}

}

Parent.inc:

#ifndef name
  #define name "Parent"
#endif name

Child.inc:

#define name "Child"

Result:

>do ##class(Macro.Parent).Test()
Class: Macro.Parent
Value: Parent
>do ##class(Macro.Child).Test()
Class: Macro.Child
Value: Child
Vitaliy Serdtsev · Dec 19, 2017 go to post

This data is saved in the registry. You can even save greater value than allowed by the program (see screenshot).

Example of work with the registry directly from Caché Object Script can be found here.

Vitaliy Serdtsev · Dec 16, 2017 go to post

For better performance you should make a few changes:

  1. add an index on DOB field
  2. rebuild the index and run TuneTable
  3. modify the query
    select DOB from HSAA.Patient
    where
    dob<=dateadd('yy',-13,current_date)
    or dob between
          todate((year(current_date)-13)||'0101','yyyymmdd')
      and todate((year(current_date)-13)||'1231','yyyymmdd')
The result will pleasantly surprise you.

Vitaliy Serdtsev · Dec 15, 2017 go to post

Hi Marco.

CSVTOCLASS creates a new class if it doesn't already exist and then it calls the Import method.

Since you already have created the class, it is not created, but there is no Import method, so nothing works.

Solution:
  1. delete all previously created classes: ZenImport.Country, TestCsv.Csv, etc.
  2. run in terminal:

    USER>set rowtype "Code VARCHAR(2),Name VARCHAR(9)"
    USER>set filename "c:\temp\Country.csv"
    USER>do ##class(%SQL.Util.Procedures).CSVTOCLASS(2, .rowtypefilename,";",,,"Test.CSV")
    
  3. run in Portal:
    select * from Test.CSV
    open and see the class "Test.CSV". Profit!!!

Vitaliy Serdtsev · Dec 14, 2017 go to post

select DOB from sample.person -- or HSAA.Patient
where
(tochar(current_date,'YYYYMMDD')-tochar(DOB,'YYYYMMDD'))\10000>=13
or ((year(current_date)||'1231')-tochar(DOB,'YYYYMMDD'))\10000=13