Eduard Lebedyuk · Jun 21, 2017 go to post

I think the most important part of source control file structure is mirroring package structure in Studio, since that is the view we spend the most time with. That said it looks something like this:

root/
    Package1/
              Class.cls
              Class2.cls
              Routine.mac
              Include.inc
     Package2/ 
              Class.cls
              Class2.cls
              Routine.mac
              Include.inc

Additionally:

  1. Web app should be stored in a separate repository.
  2. If there's docs/dictionaries/etc, then all sources should be in a /src folder instead of repository root.
  3. All libs/modules/etc should be moved into their separate repositories each and plugged in as a submodules.
  4. Builds, if any should not be stored in a repo but rather meta-managed (releases).
  5. Commit messages and granular commit history is one of the most helpful things when analysing project history, enforce commit message style (title is the most important i.e. PART/SUBPART - thing done in a commit).
Eduard Lebedyuk · Jun 21, 2017 go to post

Can you execute in SMP:

SELECT cast('0x1F' AS varbinary(1549))

Not sure why

0x1F8B08000000...

is unescaped though.

Eduard Lebedyuk · Jun 19, 2017 go to post

I would like to, on every file change export the whole project to XML

What do you want to achieve with that?

Eduard Lebedyuk · Jun 17, 2017 go to post

You can project collection property as a child table.

Property MyList as list of Object(STORAGEDEFAULT="array");

Note that it changes class storage, so existing data should be moved to the correct new place.

Several months ago I wrote a small utility class to accomplish exactly that.

Or if you don't have a lot of different classes and data dependencies, you can just export to XML, add STORAGEDEFAULT and import XML.

Eduard Lebedyuk · Jun 15, 2017 go to post

Is it possible to change underlying data model so that 1 row = 1 main object?

Class UserPrefs {

Property Username;

///  Color/Number are keys, and this can be indexed
Property Preferences As Array Of %String(SQLPROJECTION = "table/column");

Parameter ROWLEVELSECURITY = 1;

///Updated for each row when the property 'Preferences' changes
Property %READERLIST As %String [ SqlComputeCode = {set {*} = ##class(Users).%SecurityPolicy()}, SqlComputed, SqlComputeOnChange = Preferences ];

}

You can use SQL to insert into child table. Not sure if it would actually trigger a %READERLIST recalculation (maybe try %%INSERT) but worth a try.

Eduard Lebedyuk · Jun 15, 2017 go to post

16.2 has %ZEN.Auxiliary.altJSONProvider, which has same method signatures but may be preferable (faster).

Eduard Lebedyuk · Jun 13, 2017 go to post

Traced stuff to %SOAP.WebBase and for example in WriteSOAPHeaders there are these lines:

$$$XMLSetBuffer("  </"_..#SOAPPREFIX_":Header>")
$$$XMLWriteLine

I guess there's really no way to remove new lines without a very heavy customization.

Eduard Lebedyuk · Jun 13, 2017 go to post

Using SQLComputeCode and SQLComputeOnChange %READERLIST property is stored but gets recalculated on every SQL and Object INSERT/UPDATE/%Save:

Class Utils.RLS Extends %Persistent
{

Parameter ROWLEVELSECURITY = 1;

Property %READERLIST As %String [ SqlComputeCode = {set {*} = ##class(Utils.RLS).GetAccess({%%ID})}, SqlComputed, SqlComputeOnChange = (%%INSERT, %%UPDATE) ];

Property data As %String;

ClassMethod GetAccess(Id) As %String
{
    return:Id>3 "_SYSTEM"
    return "%All"
}

/// do ##class(Utils.RLS).Fill()
ClassMethod Fill(N = 5)
{
    do ..%KillExtent()
    for i=1:1:N {
        &sql(insert into Utils.RLS(data) values(:i))
    }

    zw ^demo.testD,^demo.testI

    do ##class(%SQL.Statement).%ExecDirect(,"select * from "_$classname()).%Display()
}
Eduard Lebedyuk · Jun 13, 2017 go to post

Target system is very fastidious about XML. I aim to eliminate all possible variables that may affect XML processing.

Eduard Lebedyuk · Jun 12, 2017 go to post

To get user/pass? Sure:

set sc = #class(Ens.Config.Credentials).GetCredentialsObj(.cred, "caller.class", "Ens.Config.Credentials", "CredentialsId")
write cred.Username
write cred.PasswordGet()
Eduard Lebedyuk · Jun 9, 2017 go to post

I'd start without base64 decode just to check how ftp works.

I think this would be enough to work (1st argument in Store is a full filename and second is a stream you want to put there):

ClassMethod DecodeBase64HL7ToFileFaxing(base64 As %Stream.GlobalBinary, Ancillary As %String, FileName As %String) As %String
{
    set ftp=##class(%Net.FtpSession).%New()
    if 'ftp.Connect("xxxxx","xxxxx","xxxxxx") $$$LOGINFO("Unable to connect to inteng11")
    if 'ftp.Store(FileName, base64) $$$LOGINFO("Unable to write file")
    if 'ftp.Logout() $$$LOGINFO("Failed to logout")
    quit $$$OK
}
Eduard Lebedyuk · Jun 7, 2017 go to post

Cool!

Currently all the classes are in one folder (and as there's 6 classes currently, that's ok), but is there any reason not to separate them further into folders by package?