- Stop Caché
- Start Caché in emergency access mode
- Activate UnknownUser in SMP or terminal (do ^SECURITY)
- Stop Caché
- Start Caché as usual
- Log in to post comments
When you define a query:
Query MyQuery() As %Query
{
QUERY TEXT
}Or
Query MyQuery() As %SQLQuery
{
QUERY TEXT
}That means that this query implements an interface provided by %Library.Query or %Library.SQLQuery respectively. They define method generators for Fetch/Execute/Func methods (more on them). Each method of the interface class gets called during compilation
You can subclass %Library.Query or %Library.SQLQuery to define your own methods. Here's custom query interface that does 2 things:
Class Utils.MyQuery Extends %SQLQuery { /// This method would be ran before others and changes ROWSPEC to "Id123:%String" ClassMethod %ChangeRowspec() [ CodeMode = objectgenerator, ServerOnly = 1 ] { // quit if we're not compiling a query if %mode="method" quit $$$OK set class = %class.Name set query = %compiledmethod.parent.Name set rowspec = "Id123:%String" // Modify query definition $$$defSubMemberSet(class,$$$cCLASSquery,query,$$$cQUERYparameter,"ROWSPEC",rowspec) // Modifycompiledquery definition $$$comSubMemberSet(class,$$$cCLASSquery,query,$$$cQUERYparameter,"ROWSPEC",rowspec) // Update compile-time parameter value set %parameter("ROWSPEC") = rowspec // Update class definition do UpdClsDef^%occLibrary(class) quit $$$OK } /// GetText is a method that is used to get query text as a %String ClassMethod GetText() As %String [ CodeMode = objectgenerator, ServerOnly = 1 ] { if %mode="method" quit $$$OK $$$comMemberKeyGetLvar(query,%classname,$$$cCLASSquery,%property,$$$cQUERYsqlquery) do %code.WriteLine(" quit " _ $$$quote(query)) quit $$$OK } }
And here's a test class with our new query:
Class Utils.MyQueryTest
{
Query ABC() As Utils.MyQuery
{
SELECT 1
}
}After Utils.MyQueryTest is compiled it looks like this:
Class Utils.MyQueryTest
{
Query ABC() As Utils.MyQuery(ROWSPEC = "Id123:%String")
{
SELECT 1
}
}You can modify this interface to get any behavior you want.
Code is available on GitHub.
What about it?
It says that class methods can be jobbed as ..Method() instead of ##class(Package.Class).Method(), if we're in a class context.
Please consider clarifying your question.
InterSystems Caché is a database, so adding 200 fields is fairly straightforward.
InterSystems Ensemble is a ESB. It has Business Hosts (Business services, Business processes, Business operations). They manipulate data stored in Caché database based on arbitrary rules.
Only class methods can be used for jobs, otherwise where does the object belong - to a parent or child process?
Func is documented in release notes, and in a queries interface class. But I do agree that it's fairly difficult to find without prior knowledge of it (I searched for Func keyword).
what is ExtentFunc?
For each persistent class there is an Extent class query that returns IDs.
For Sample.Employee class it is:
SELECT ID, Name, SSN, Home_City, Home_State FROM Sample.Employee
For each class query, <QueryName>Func method gets generated.
You can see it in the class int code using Show Other View (Open Sample.Employee and press Ctrl+Shift+V).
Here's the generated <QueryName>Func method for the Extent query of the Sample.Employee class:
zExtentFunc() public {
try {
set tSchemaPath = ##class(%SQL.Statement).%ClassPath($classname())
set tStatement = ##class(%SQL.Statement).%New(,tSchemaPath)
do tStatement.prepare(" SELECT ID , Name , SSN , Home_City , Home_State FROM Sample . Employee")
set tResult = tStatement.%Execute()
}
catch tException { if '$Isobject($Get(tResult)) { set tResult = ##class(%SQL.StatementResult).%New() } set tResult.%SQLCODE=tException.AsSQLCODE(),tResult.%Message=tException.AsSQLMessage() }
Quit tResult }It executes the query and returns result set. More on class queries.
class %sqlcq.SAMPLES.cls9
To see the code:
Ensemble runs under other user, so:
1. Compare environment variables from terminal and Ensemble (path is especially important):
do $zf(-1,"set > vars.txt")
2. Check that ensemble can access all required files.
3. Check working directory.
4. (Optional) Provide full paths to all files and binaries.
Sample.Company and Sample.Employee share one company/many employees relationship.
Do you want to iterate over employees and display a company name for each?
set rs = ##class(Sample.Employee).ExtentFunc()
while rs.%Next() { set emp = ##class(Sample.Employee).%OpenId(rs.ID) w emp.Company.Name,! }You can even get company names even without opening objects:
set rs = ##class(Sample.Employee).ExtentFunc()
while rs.%Next() { w ##class(Sample.Company).NameGetStored(##class(Sample.Employee).CompanyGetStored(rs.ID)),! }Fixed.
Thank you!
Here's a method to get OS environment variable:
write $System.Util.GetEnviron(VariableName)
I mean pertaining to this article.
So far NodeJS is only used as a general dev environment and build pipeline manager.
Maybe front-end would communicate with Caché backend via REST API? Or websockets?
You can convert binary openssl output to base64 and write that to file:
s cmd=$$$FormatText("openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -sign %1 %2 | base64 > %3",fileKey,fileMsg,file64)base64 is available in most linux flavors, and on Windows in various GNU CoreUtils builds and in Git (usually under C:\Program Files\Git\usr\bin\).
Also in an a business operation filenames should be generated randomly (probably via ##clss(%File).TempFilename(ext)) to avoid conflicts.
Export relevant globals to xml file(1 file per namespace) and compare hash sums. Also there's a lot of tools to display XML diffs if hash sums would differ.
Otherwise it's per global iteration and compare. I'd write some method to calculate global hash maybe (complete iteration and hash of keys and value). So:
I didn't know that
#include %occCPTJSgen
Redefines $$$TAB. Seems useful. Thanks.
Please note that $$$TAB macro is actually a whitespace:
ClassMethod GetTab() [ CodeMode = expression ]
{
$$$TAB
}
Call to GetTab returns:
USER>zzdump ##class(Utils.Persistent).GetTab() 0000: 20
I usually use either $c(9) or user-defined macro for tabulation.
do ##class(%Compiler.UDL.TextServices).GetTextAsString(namespace, class, .text) write text
You can write custom queries and create custom result sets that iterate over globals, etc. and expose them via ODBC.
Make plaintext property triggered computed on insert/update rather than always computed.
Property PlainText As %String(MAXLEN="") [ SqlComputeCode = {set {*} = ##class(%iKnow.Source.Converter.Html).StripTags({HtmlText}}, SqlComputed, SqlComputeOnChange = (%%INSERT, %%UPDATE) ];There's no need to search for the /s1/s2/s3 in the second template, as the first template would send every node into the second template. So your XSLT should probably look like this:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="//@* | //node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//s3" >
<xsl:copy>
<xsl:apply-templates select="@*"/>
Content Replaced
</xsl:copy>
</xsl:template>
</xsl:stylesheet>As both Angular and Zen manage page state, combining them it does not seem particularly promising.
Thank you, Benjamin.
I thought TRANSFORMATIONSPEC parameter could have been used somehow, but I'll try your suggested approach.
Are these (Caché and Ensemble) systems in production or development?
Emsemble is Caché + Some classes. So the easiest solution would be to move Caché application into Ensemble instance.
Example of calling Ensemble from Caché is available in Demo.ZenService.Zen.WeatherReportForm class, GetWeatherReport method in ENSDEMO namespace.
Probably not.
Here's Ensemble Event Log Viewer with multi-namespace support. In uses custom query to pull data from different namespaces.