Eduard Lebedyuk · Oct 25, 2017 go to post

Hello, Amir!

Can ECP be configured in the case where one of the server is on the internal network? So server1 can see and get replies from server2 but server2 can't access server1 by itself?

Eduard Lebedyuk · Oct 20, 2017 go to post

You need to parse CSV. Here's how to do that in Caché:

Provided you have this csv:

car,2000,100.51,27.10.2016,
phone,2003,65.8,15.01.2017,

You can import it into class Test.CSV:

1. Generate a persistent class Test.CSV

set rowtype = "name VARCHAR(50),year INTEGER,amount NUMERIC(9,2),date DATE"
set filename = "D:\data.csv"
do ##class(%SQL.Util.Procedures).CSVTOCLASS(2, .rowtype, filename,,,,"Test.CSV")

2. Import file or files

do ##class(Test.CSV).Import(2,filename)

Usually you can't import your CSV right away - the dates are in a different format, etc. You need to modify Import method and property definitions. For example I often:

  • Add FORMAT=4 property parameter for dates to import dates in dd/mm/yyyy format.
  • Find&replace Library.
  • Add this else line in Import method:
if $$$ISOK(tStatus) { set tCounter = tCounter + 1 } else { w $System.Status.GetErrorText(tStatus) return}

If you have a tab separated file, you need to change Import method signature from:

pDelimiter As %String = ","

to:

pDelimiter As %String = {$c(9)}

You may need to additionally modify Import method to accept streams instead of files.

Eduard Lebedyuk · Oct 20, 2017 go to post

Additionally in web app settings specify:

  • Serve Files: Always
  • Serve Files Timeout: 0

Note, that it would disable caching completely.

Eduard Lebedyuk · Oct 17, 2017 go to post

Not sure if choiceGetCount is a public API to do that.

You want to count a number of occurances of a particular node in some path?

Eduard Lebedyuk · Oct 17, 2017 go to post

Simplified example:

set xml = ##class(EnsLib.EDI.XML.Document).%New().ImportFromString("<root><RepeatingElement>Content</RepeatingElement><RepeatingElement>Content</RepeatingElement></root>") 
Eduard Lebedyuk · Oct 16, 2017 go to post

As you can see in the documentation, method OutputToIOStream returns a status and not a stream (first argument - a stream is written to in this method), so you should write:

Set pIOStream = ##Class(%IO.StringStream).%New()
Set tSC = pRequest.OutputToIOStream(pIOStream,..Separators,"",1)
Quit:$$$ISERR(tSC) tSC
Set tSC = mail.AttachStream(pIOStream,..Filename,1,"iso-8859-1")
Quit tSC
Eduard Lebedyuk · Oct 16, 2017 go to post

Are you just selecting the property? If so can you please provide property definition.

Eduard Lebedyuk · Oct 15, 2017 go to post

RawContent is a string, from docs:

The raw text content of the document. Note that this is a truncated version suitable for use in SQL results and visual inspection, but not a complete or definitive representation of the document.

To get  message as a stream use OutputToIOStream method in EnsLib.HL7.Message class.

Eduard Lebedyuk · Oct 14, 2017 go to post

That does not seem to be possible. Why not JOIN them directly?

SELECT *
FROM Sample.Employee e
LEFT JOIN Sample.Company c ON c.id = e.id
JOIN Sample.Vendor v ON v.%id = c.attr
Eduard Lebedyuk · Oct 13, 2017 go to post
ClassMethod SetNamespace(user As %String = {$username}, namespace As %String = {$namespace})
{
   new $namespace
   set $namespace = "%SYS"
   set user = ##class(Security.Users).%OpenId($zcvt(user,"l"))
   set user.Namespace = namespace
   quit user.%Save()
}

You should probably add input validation.

Eduard Lebedyuk · Oct 12, 2017 go to post

Resources property is not evaluated. You can see that in %Installer.Role class, %OnGenerateCode method.

/// Generate code for this document.
Method %OnGenerateCode(pTargetClass As %Dictionary.CompiledClass, pCode As %Stream.TmpCharacter, pDocument As %Installer.Manifest) As %Status [ Internal ]
{
Do pCode.WriteLine(..%Indent()_"Do tInstaller.CreateRole($$$EVAL("_..Target_"),$$$EVAL("_..Description_"),"""_..Resources_""","""_..RolesGranted_""")")
Quit $$$OK
}

You can get around that with this hacky solution:

 <Role
Name="${PMGNAMESPACE}"
Description="Works User Role for ${PMGNAMESPACE} Namespace"
Resources='"_tInstaller.Evaluate("${PMGDbResource}:RW,PMG:RWU")_"' RolesGranted="" />

Which would be compiled into the following code:

 Do tInstaller.CreateRole(tInstaller.Evaluate("${PMGNAMESPACE}"),tInstaller.Evaluate("Works User Role for ${PMGNAMESPACE} Namespace"),""_tInstaller.Evaluate("${PMGDbResource}:RW,PMG:RWU")_"","")

I guess if you need to do that once, it's okay. But if it's a regular occurrence writing a method and calling it from installer might be a better solution.

Here's an article on %Installer usage.

Eduard Lebedyuk · Oct 10, 2017 go to post

Not sure about delegated authentication (is it only delegated? Or with password? Details may vary depending on your exact setup), but for password authenticated web application SSO is possible by following these steps (originally written for CSP+REST web apps, but the idea is the same):

  1. All brokers effectively have Parameter UseSession = 1;
  2. REST web application and client web application allow only authenticated (i.e. password) access.
  3. REST web application and client web application have reasonable Session timeout (i.e. 900, 3600).
  4. REST web application and client web application have the same GroupById value.
  5. REST web application and client web application have the same cookie path.

If all these conditions are met, user would only consume one license slot per session and perform only one login and audit database would store only one login event per session.

Eduard Lebedyuk · Oct 9, 2017 go to post

Here's how you can import CSVs into Caché without writing any code yourself. I recommend this approach.

In your example, replace:

set adapter = ##class(%File).%New()
set status = adapter.%Open("C:\In\in.csv")

with:

set adapter = ##class(%File).%New("C:\In\in.csv")
set status = adapter.Open("R")

Check out the documentation for %File class.

Eduard Lebedyuk · Oct 9, 2017 go to post

CAPTION  and COLLATION are default property parameters that you can add to any property.

Eduard Lebedyuk · Oct 7, 2017 go to post

Compare what user entered to the specific value. If they mismatch  - ask again. Also there are several utility methods in %Prompt class for number/yes-no/etc input:

  • GetNumber
  • GetString
  • GetYesNo
  • GetArray - Prompt for a number or entry in a displayed menu. Returns the selected item.
  • GetMenu - Prompt for a number in a displayed menu.
  • GetMore - Prompt for More or Quit.

For example:

do ##class(%Prompt).GetYesNo("Enter Yes or No:", .result)

User can input only Yes (Y) or No (N). result variable would hold 1 or 0.

You can also check %Prompt code and write something based on that.

Eduard Lebedyuk · Oct 7, 2017 go to post

This can be done with SQL procedure:

Query SomeQuery() As %SQLQuery
{
SELECT ID || SomeClass.GetParam('SomeClass', 'SOMENAME') FROM Table
}

ClassMethod GetParam(class, param) As %String [ CodeMode = expression, SqlProc ]
{
$parameter(class, param)
}