go to post Timothy Leavitt · Feb 16, 2016 This has been bothering me a little bit; %Dictionary.* should really be a last-resort option, in my opinion, and it isn't easy to use it to get the full picture from an SQL perspective.Here are some alternative/possibly-better solutions, using %SQL.StatementMetadata and INFORMATION_SCHEMA. It looks like INFORMATION_SCHEMA is more exactly what you were looking for, if you're running on a recent enough Caché version (2015.1+). I haven't been able to find documentation on it other than the class reference, though. /// NOTE: It could be good to validate pTableName to avoid SQL injection. (Outside the scope of this demo.)/// This works pre-2015.1 (since %SQL.Statement was introduced - maybe 2012.2+?)ClassMethod GetTableColumns(pTableName As %String) As %List{ #dim tResult As %SQL.StatementResult #dim tMetadata As %SQL.StatementMetadata Set tStmt = ##class(%SQL.Statement).%New() $$$ThrowOnError(tStmt.%Prepare("select top 0 * from "_pTableName)) Set tResult = tStmt.%Execute(), tMetadata = tResult.%GetMetadata() Set tCols = "" For i=1:1:tMetadata.columnCount { Set tCols = tCols_$ListBuild(tMetadata.columns.GetAt(i).colName) } Quit tCols}/// This will only work on 2015.1+; INFORMATION_SCHEMA is a new feature. For more information, see the class reference for it in the documentation.ClassMethod GetTableColumnsNew(pTableName As %String) As %List{ #dim tResult As %SQL.StatementResult Set tStmt = ##class(%SQL.Statement).%New() Set tSchema = $Piece(pTableName,".") Set tTableName = $Piece(pTableName,".",2) $$$ThrowOnError(tStmt.%Prepare("select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?")) Set tResult = tStmt.%Execute(tSchema,tTableName) Set tCols = "" While tResult.%Next(.tSC) { Set tCols = tCols_$ListBuild(tResult.%Get("COLUMN_NAME")) } $$$ThrowOnError(tSC) Quit tCols}Using this:SAMPLES>set cols = ##class(Demo.TableColumns).GetTableColumns("Sample.Person")SAMPLES>w $lts(cols)ID,Age,DOB,FavoriteColors,Name,SSN,Spouse,Home_City,Home_State,Home_Street,Home_Zip,Office_City,Office_State,Office_Street,Office_ZipSAMPLES>set cols = ##class(Demo.TableColumns).GetTableColumnsNew("Sample.Person")SAMPLES>w $lts(cols) ID,Age,DOB,FavoriteColors,Name,SSN,Spouse,Home_City,Home_State,Home_Street,Home_Zip,Office_City,Office_State,Office_Street,Office_Zip
go to post Timothy Leavitt · Feb 12, 2016 Perhaps try: SELECT NVL(SqlFieldName,Name) FROM %Dictionary.CompiledProperty WHERE parent = 'HS.IHE.ATNA.Repository.Aggregation' and Transient = 0 %Dictionary.PropertyDefinition only includes properties defined in a given class; %Dictionary.CompiledProperty includes properties that are inherited.
go to post Timothy Leavitt · Feb 10, 2016 I agree. In some cases, having an initial default value determined when the object is saved - possibly based on values of other properties, which InitialExpression wouldn't allow - could be useful, if that's how SqlComputed + SqlComputeCode is expected to work. This probably isn't one of those cases.
go to post Timothy Leavitt · Feb 9, 2016 In various posts, you've talked about having an implementation tool that is run from the browser, and you've also talked about running it from terminal. Here's a design that would be well-suited to both:* Settings that apply to the whole thing are properties of an object (class extends %RegisteredObject)* There's a class method (static method in other languages) to get the settings' values interactively* There's an instance method to run the setup on an instance of the class Include %syPromptClass Demo.SetupTool Extends %RegisteredObject{Property Type As %String(VALUELIST = ",Gateway,IHE");Property Setting1Value As %String [ InitialExpression = "ABC" ];Property Setting2Value As %Boolean [ InitialExpression = 1 ];ClassMethod RunInteractive(){ Set tSettingsObject = ..%New() Write "Deployment Utility" Set options(1) = "Gateway" Set options(2) = "IHE" Do ##class(%Prompt).GetArray("Deployment Type?",.tType,.options,,,,$$$InitialDisplayMask+$$$MatchArrayMask) Set tSettingsObject.Type = tType Set tString = tSettingsObject.Setting1Value Do ##class(%Prompt).GetString("Enter a string: ",.tString) Set tSettingsObject.Setting1Value = tString Set tYesOrNo = tSettingsObject.Setting2Value Do ##class(%Prompt).GetYesNo("Is this a helpful demo? ",.tYesOrNo) Set tSettingsObject.Setting2Value = tYesOrNo Do tSettingsObject.DoSetup()}Method DoSetup(){ Write !,"Starting ",..Type," deployment...",! // Here, do things based on properties of this object. If '..Setting2Value { //Do something specific if Setting2Value is false. Write "Why not?",! }}} Then, for example:USER>d ##class(Demo.SetupTool).RunInteractive()Deployment Utility 1) Gateway2) IHE Deployment Type? 1 GatewayEnter a string: ABC =>Is this a helpful demo? Yes => NoStarting Gateway deployment...Why not? Or, if you want to do the same kind of setup from a simple ZenMethod in a Zen page or something, you could set up a settings object and then call DoSetup() on it.USER>set tSettings = ##class(Demo.SetupTool).%New() USER>set tSettings.Type = "IHE" USER>d tSettings.DoSetup() Starting IHE deployment...
go to post Timothy Leavitt · Feb 8, 2016 Here's some relevant documentation: http://docs.intersystems.com/cache20152/csp/docbook/DocBook.UI.Page.cls?KEY=GORIENT_ch_cos#GORIENT_cos_scope One way to make this work as-is would be to put tstVar in the "public" list: start set tstVar = "Green" do TestIt() TestIt() [tstVar] { write tstVar } Another would be to give the variable a name starting with a %: start set %tstVar = "Green" do TestIt() TestIt() { write %tstVar }
go to post Timothy Leavitt · Feb 8, 2016 Look at $zconvert (abbreviated $zcvt): http://docs.intersystems.com/cache20152/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fzconvert For example: USER>w $zcvt("thisIsATest","U") THISISATEST USER>w $zcvt("thisIsATest","L") thisisatest
go to post Timothy Leavitt · Feb 5, 2016 You could probably download the single-user evaluation version of Caché to get a look at the SAMPLES namespace, go through tutorials, etc - see https://download.intersystems.com/ For understanding routines in general, I'd recommend this part of the documentation.
go to post Timothy Leavitt · Feb 5, 2016 It is in the 2015.2 documentation (you linked to 2010.1): $$$MatchArrayMask - Only entries from the array of options are allowed, not case sensitive Update: It looks like it first showed up in 2013.1.
go to post Timothy Leavitt · Feb 5, 2016 "GOTO label" jumps to a specified label in the same context frame."DO label" adds a new context frame. Code at the specified label will execute until a QUIT/RETURN or the end of the routine, then execution will resume at the next line after the DO command.So in this case it's running through the whole routine (including everything under the dataentry label, with dtype already set to something valid), including printing the message at the end. Then it proceeds to the next thing after the DO command, which is printing that line again.For what it's worth, if you're building command-line tools, %Library.Prompt may save you a lot of time. See the class reference for more informatioan.For example: #include %syPrompt New options,dtype Write "Deployment Utility" Set options(1) = "Gateway" Set options(2) = "IHE" Do ##class(%Prompt).GetArray("Deployment Type?",.dtype,.options,,,,$$$InitialDisplayMask+$$$MatchArrayMask) Write !, "Starting ", dtype," deployment..." Quit
go to post Timothy Leavitt · Feb 5, 2016 Nope, it's a Drupal thing: https://www.drupal.org/project/radioactivity
go to post Timothy Leavitt · Feb 4, 2016 At a Caché level (for namespaces, databases, code, and security), %Installer may be useful; see: http://docs.intersystems.com/cache20152/csp/docbook/DocBook.UI.Page.cls?KEY=GCI_manifest For Ensemble, there are some additional deployment-related features that might do more for you in terms of settings and lookup tables. See: http://docs.intersystems.com/ens20152/csp/docbook/DocBook.UI.Page.cls?KEY=EGDV_deploying#EGDV_deployment_overview
go to post Timothy Leavitt · Jan 21, 2016 It looks like that method only exists in Caché 2015.2.0+. You're probably running on an older version. (write $zversion?)
go to post Timothy Leavitt · Jan 21, 2016 Another option, and a caveat about ^%SYS("SystemMode"): It looks like you're using CCR.* "Environment" is a meaningful term in that context. In namespaces configured for CCR, you can retrieve the environment with $$Env^%buildccr, i.e.: CCR>w $$Env^%buildccr BASE It is possible to have multiple namespaces on the same instance configured as different environments. ^%SYS("SystemMode") is set to the furthest-along environment (of BASE-TEST-LIVE) of any namespace on the instance. That is, if you have a namespace configured as BASE, and configure another one as TEST, ^%SYS("SystemMode") will be changed to TEST - and this is system-wide. Just something to keep in mind. *CCR (Change Control Record) is an InterSystems in-house application used in sites where InterSystems does implementation work, so this isn't as generally relevant as ^%SYS("SystemMode").
go to post Timothy Leavitt · Jan 20, 2016 I tend to use %INLIST $ListFromString(?) in cases like this. (Assuming that the list is something like IDs that wouldn't contain commas.) So, in your example: <tablePane width="25%" id="testTable" sql="SELECT Id from Tracking_Data.Person WHERE Id %INLIST $ListFromString(?)" showQuery="true"> <parameter/> </tablePane> <button caption="Test" onclick="zenThis.composite.testTestTable();"/> ClientMethod testTestTable() [ Language = javascript ] { var table = zenThis.composite.getChildById("testTable"); table.setProperty('parameters', 1, '1,2'); }
go to post Timothy Leavitt · Jan 20, 2016 This should definitely work. Are you setting the showTabBar property to true for the nested tabGroup? If not, that might explain why nothing is showing up.
go to post Timothy Leavitt · Dec 18, 2015 I did a project similar to this using %Net.POP3 a few years back (internal ref: ISCX2452), but it's part of a much larger application, so the exact code probably would not be very useful.The general pattern for using %Net.POP3 is: set tSC = server.Connect(servername,username,password) set tSC = server.GetMailBoxStatus(.numberOfMessages) for i=1:1:numberOfMessages { set tSC = server.Fetch(i,.msg) //msg is a %Net.MailMessage //optional: set tSC = server.DeleteMessage(i) } //IMPORTANT! QuitAndCommit() or QuitAndRollback() set tSC = server.QuitAndCommit()Add your own status-checking, try/catch, etc. One important caution: always be careful to clean up the connection when you're done, with either QuitAndRollback or QuitAndCommit. This might be the cause of the error you noted in your last comment - an open connection could be left over from before, blocking additional connections. I think terminating the process will fix this. (I remember this causing all sorts of trouble/confusion on my old project.)As a side note: if your application/use case is running on Ensemble, EnsLib.EMail.InboundAdapter will do a lot of the hard work for you. See for reference: http://docs.intersystems.com/ens20152/csp/docbook/DocBook.UI.Page.cls?KE...This adapter will delete successfully-processed e-mails. From a "syncing" perspective this keeps things simple. If you don't want the messages deleted, a simple workaround might be to subclass EnsLib.EMail.InboundAdapter and %Net.POP3, override DeleteMessage to make it a no-op in the %Net.POP3 subclass, and override the adapter's MailServer property to use your %Net.POP3 subclass. (This would be a bit less messy than overriding OnTask.)