If you are familiar (proficent) with ZEN use ZEN Mojo.
If not, write HTML/JS/CSS client and REST server.
That said, DeepSee would definitely be an easier solution to implement and more robust overall.
- Log in to post comments
If you are familiar (proficent) with ZEN use ZEN Mojo.
If not, write HTML/JS/CSS client and REST server.
That said, DeepSee would definitely be an easier solution to implement and more robust overall.
REST service can be implemented in Caché itself, via %CSP.REST. Documentation.
OnStart gets executed before queries, see Ens.Director class, StartProduction method.
Or you can execute EnableConfigItem on an item of a disabled production.
Triggers are, unfortunately, not an option as MySQL table gets updated via backup (so it's DROP TABLE -> CREATE TABLE -> INSERT)
Thanks.
In regards to the documentation, I'd like to clarify that it refers to a database page accessible at
SMP → System Operation → Databases, and not SMP → Menu → Configure Databases.
It may be useful as one of the metrics related to the code quality/monitoring.
For example, my continuous integration system Cache GitHub CI tracks compile time for each commit, and if it suddenly grows, then the offending commit may be worth looking into. But if we add one other metric - "lines of code added", then some of the offending commits may be removed based on a now determinable fact that a raise in compilation time is caused by a project size increase.

On the screenshot: compilation time (Length column) for some commits in a real-life project.
Other usage - find classes longer than, for example, 500 sloc and separate them into several classes.
Cache version?
Your code runs without errors on 2016.1.
What value are you trying to decode?
I mean can you post it (or any other base64 string giving you an error) here?
I seem unable to reproduce the error.
Your input is too long, so it's not a string but rather %CSP.CharacterStream.
"val" should be in Upper case I suppose?
No. IndexOpen calls IndexExists to get object ID. In IndexExists "val" is matched to corresponding ID with the following SQL expression (except for IDKEYExists. It calls %ExistsId):
SELECT %ID INTO :id FROM Package.Class WHERE (val IS NOT NULL AND IndexProperty = val) OR (val IS NULL AND IndexProperty IS NULL)
The interesting question would be - why not traverse index global to get id instead of using SQL?
Sure did. To clarify, it's the fastest way available by default. The fastest way is a direct global reference (provided of course that we do not have the object in a context already available), but we need to either hardcode the global reference or calculate it at compile time. Here's the test class (I won't copy it here - it's fairly long). The results are like this:
Iterations: 10000 Object access: .130111 GetStored access: .014388 SQL access: .020268 Global access: .007717 Object access takes 904.30% of GetStored time Object access takes 641.95% of SQL time Object access takes 1686.03% of Global time GetStored access takes 70.99% of SQL time GetStored access takes 186.45% of Global time SQL access takes 262.64% of Global time
Where:
One piece of code I'd like to share here is the macro to get global reference for a property by a class and property name:
Class Utils.GetStored Extends %Persistent
{
Property text As %String;
ClassMethod Global() As %Status
{
#Define GetStoredProp(%cls,%prop,%idvar) ##Expression(##class(Utils.GetStored).GetPropGLVN(%cls,%prop, $name(%idvar)))
Set Id = $Random(999)+1
Set Val = $$$GetStoredProp("Utils.GetStored","text", Id)
}
/// Write ##class(Utils.GetStored).GetPropGLVN("Utils.GetStored", "text")
ClassMethod GetPropGLVN(Class, Property, IdVar = "id") As %String
{
Set StoredCode = $Get($$$EXTPROPondisk($$$pEXT,Class,Property))
Set StoredCode = $Replace(StoredCode, "(id)", "(" _ IdVar _ ")")
Return StoredCode
}On compilation the string with $$$GetStoredProp macro would be compiled into:
Set Val = $listget($g(^Utils.GetStoredD(Id)),2) This problem can be reproduced on all infinite scroll pages. The particular page I reported is just an example.
Another question what is the sense to check "val" for IS NULL for Unique Index?
This check, if hit returns first Id with empty val.
So, "val" should exactly match the value of property, case sensitive?
That depends on property collation. For EXACT/ TRUNCATE/SQLSTRING collation, yes "val" should exactly match the value of the property (compared part of the value), case sensitive. For SQLUPPER - no.
Please clarify your question.
DeepSee supports a hierarchical structure of grouping. Where do you want it? In the Architect or Analyzer pivot?
DeepSee cube definitions and pivots in Samples offer many examples.
Here's the list of all intrinsic member properties:
Well, that depends.
Currently use it, and it's awesome. It also supports connection over ssh.
I need "u" flag in studio. During compilation the flags from user (studio) are combined with namespace or system flags. So even if I set namespace default flags without "u", the compiler would still use this flag as it is present in studio.
tParams should be an array:
set tParms("tExperssion") = tExperssion
set tParms("tIndex") = tIndexand this line:
<xsl:copy-of select="$tExperssion"/>
should maybe be:
<xsl:value-of select="$tExperssion"/>Here's working example:
Class Sample.XSLTransform [ Abstract ]
{
ClassMethod test(tData = "<HHSOS><DIAGNOSES><DIAGNOSIS_DATA><DIAGNOSIS_DATA_GUID>3762875</DIAGNOSIS_DATA_GUID><DIAGNOSIS_DATA_GUID>37628752</DIAGNOSIS_DATA_GUID></DIAGNOSIS_DATA><DIAGNOSIS_DATA></DIAGNOSIS_DATA><DIAGNOSIS_DATA></DIAGNOSIS_DATA><DIAGNOSIS_DATA_GUID>37628753</DIAGNOSIS_DATA_GUID></DIAGNOSES></HHSOS>", tSelect = "//DIAGNOSIS_DATA_GUID[1]", tXSL = "ExampleXSL")
{
set tXML= ##class(%GlobalCharacterStream).%New()
do tXML.Write(tData)
set tXSL=##class(%Dictionary.CompiledXData).%OpenId($classname() _ "||" _ tXSL ).Data
kill tParams
set tParams("selectParam") = tSelect
set tSC=##class(%XML.XSLT.Transformer).TransformStream(tXML,tXSL,.tOutput,,.tParams)
zwrite tSC
set tSC=tOutput.OutputToDevice()
}
XData ExampleXSL
{
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="selectParam"/>
<xsl:template match="/">
<xsl:copy-of select="$selectParam"/>
</xsl:template>
</xsl:stylesheet>
}
}Example:
Do ##class(Sample.XSLTransform).test() tSC=1 <?xml version="1.0" encoding="UTF-8"?><DIAGNOSIS_DATA_GUID>3762875</DIAGNOSIS_DATA_GUID><DIAGNOSIS_DATA_GUID>37628753</DIAGNOSIS_DATA_GUID>
Why use JSON object instead of a usual signature?
Method %Connect(IP = "127.0.0.1", Port = {^%SYS("SSPort")}, Namespace = "%SYS", Username, Password, ClientIP, ClientPort ) As Sample.RemoteProxy
{
}Also, it can be moved into the %OnNew method.
This is not, generally a good idea to insert potentially long and slow code inside of object constructor.
Why? %OnNew should contain code which is absolutely required on object initiation regardless of the execution speed. There is no use case for this class to construct an object and not call %Connect, so %Connect should be moved into %OnNew. That way client code needs to make one mandatory call instead of two.
Added a demo class.
That's useful.
set %Stream=##class(%Stream.TmpCharacter).%New()
Is there any particular reason to use % variable here? I think local variable would be enough.
I meant you write them. Here's the reference though.
I removed InvalidGet method and object access to the property stopped working.
Class Utils.GlobalProp Extends %Persistent
{
Parameter InvalidGLVN = "^Utils.GlobalPropP";
Property Invalid As %String [ SqlComputeCode = {set {*} = ##class(Utils.GlobalProp).InvalidStatic()}, SqlComputed, Transient ];
ClassMethod InvalidStatic() As %String
{
Return $Get(@..#InvalidGLVN)
}
Method InvalidSet(val As %String) As %Status
{
Set @..#InvalidGLVN = val
Return $$$OK
}
/// Do ##class(Utils.GlobalProp).Test()
ClassMethod Test()
{
Do ..%KillExtent()
Set obj = ..%New()
Write "Invalid old: " _ obj.Invalid,!
Set obj.Invalid = $Random(100)
Write "Invalid new: " _ obj.Invalid,!
Do obj.%Save()
Kill obj
&sql(SELECT Invalid INTO :invalid FROM Utils.GlobalProp WHERE Id = 1)
Write "SQLCODE: " _ SQLCODE,!
Write "Invalid sql: " _ invalid,!
}Outputs:
Invalid old: Invalid new: SQLCODE: 0 Invalid sql: 65
Related Int code:
zInvalidCompute(%id)
New %tException,%val set %val = ""
try {
set %val = ##class(Utils.GlobalProp).InvalidStatic()
} catch %tException { throw %tException }
Quit %val
zInvalidGet() public {
If i%Invalid = "" { Set ..Invalid=..InvalidCompute($listget(i%"%%OID")) } Quit i%Invalid }
zInvalidSQLCompute()
// Compute code for field Invalid
set %d(2) = ##class(Utils.GlobalProp).InvalidStatic()
QUIT
Do $System.Status.DisplayError(tStatus)
Write !
}
Quit
}
}