go to post Eduard Lebedyuk · Jul 28, 2016 Okay, then you need to use your original storage definition, but when selecting invalid, select it in a NVL function: SELECT ID, Code, Description, NVL(Invalid, 0) FROM Wendy.LTCodes It should return 0 instead of empty string.
go to post Eduard Lebedyuk · Jul 27, 2016 Runtime Variables are for that purpose.And if you want to apply filter to any MDX query against a cube, you can specify a %OnGetFilterSpec callback.
go to post Eduard Lebedyuk · Jul 26, 2016 These changes fixed it: Removed highlited part of storage definitionMade invalid property TransientAdded 0 default to $Get Class Wendy.LTCodes Extends %Persistent [ StorageStrategy = LTCStorage ] { Property Code As %String; Property Description As %String; Property Invalid As %Library.Boolean [ SqlComputeCode = { set {*} = ##class(Wendy.LTCodes).GetInvalid({Code})}, SqlComputed, Transient ]; Index CodeIndex On Code [ IdKey, PrimaryKey, Unique ]; ClassMethod GetInvalid(WSCode) As %Boolean { Quit $G(^LTCODES(WSCode,"INVALID"),0) } Method InvalidGet() As %Boolean { Quit ..GetInvalid(i%Code) } Method InvalidSet(value As %Boolean) As %Status { Set ^LTCODES(i%Code,"INVALID")=value quit $$$OK } /// Do ##class(Wendy.LTCodes).SetData() ClassMethod SetData() { kill ^LTCODES S ^LTCODES("N001")="ANYOLD DESC" S ^LTCODES("N001","INVALID")=1 S ^LTCODES("N002")="C5 REPEAT 1" S ^LTCODES("N111")="SPECIMEN COMMENT" S ^LTCODES("N200")="MSUD SCREEN|MSUD" S ^LTCODES("N500")="Sickle Cell Screen" } Storage LTCStorage { <SQLMap name="LTCMap"> <Data name="Description"> <Delimiter>"|"</Delimiter> <Piece>1</Piece> </Data> <Global>^LTCODES</Global> <Subscript name="1"> <Expression>{Code}</Expression> </Subscript> <Type>data</Type> </SQLMap> <StreamLocation>^Wendy.LTCodesS</StreamLocation> <Type>%CacheSQLStorage</Type> } }
go to post Eduard Lebedyuk · Jul 26, 2016 I imported your example, executed: Do ##class(Wendy.LTCodes).SetData() Then executed this sql: SELECT ID, Code, Description, Invalid FROM Wendy.LTCodes and received the following results: IDCodeDescription InvalidN001N001ANYOLD DESC1N002N002C5 REPEAT 1 N111N111SPECIMEN COMMENT N200N200MSUD SCREEN N500N500Sickle Cell Screen seems to be working. But then I didn't really understand the use of Parameter InvalidGLVN = "^Utils.GlobalPropP"; it's for use with indirection. Example: set ^Utils.GlobalPropP = 123 set glvn = "^Utils.GlobalPropP" write glvn > ^Utils.GlobalPropP write @glvn > 123
go to post Eduard Lebedyuk · Jul 26, 2016 Your error: <INVALID 0REF>zSrvGetData+2 Points to the line; set item = ..%GetComponentById("Item").value And means that the result of this call: ..%GetComponentById("Item") Is not an object, so you can't access a property "value".
go to post Eduard Lebedyuk · Jul 26, 2016 You can define a property of %Stream.Object class and store %Stream.FileBinary/%Stream.FileCharacter there.
go to post Eduard Lebedyuk · Jul 25, 2016 Why not use %Stream.FileBinary and %Stream.FileCharacter? It would store the file outside of the database.
go to post Eduard Lebedyuk · Jul 25, 2016 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 } }
go to post Eduard Lebedyuk · Jul 23, 2016 If our SVN repository already is storing discrete .cls files, does Atelier do any conversion when we load from SVN into our server instance?No, except maybe for repository structure. That depends is Atelier + EGit support repository structure you use. For how to use EGit with Atelier check this article.At what point would I see .udl files? I am thinking I would only see that if SVN was storing .xml and each of those would be converted to .udl.There are no .udl files. There are just cls/mac/inc etc files in udl format, meaning they are represented on disk as is and not in the xml format. The extension would be .cls and so on. Here's the sample repository created with Atelier.
go to post Eduard Lebedyuk · Jul 22, 2016 Getter and Setter are object related concepts, SQL does not use them. You can, however specify SqlComputeCode for SELECT access to a property. This example stores and retrieves Invalid property value from ^Utils.GlobalPropP global. Class Utils.GlobalProp Extends %Persistent { Parameter InvalidGLVN = "^Utils.GlobalPropP"; Property Invalid As %String [ SqlComputeCode = {set {*} = ##class(Utils.GlobalProp).InvalidStatic()}, SqlComputed, Transient ]; Method InvalidGet() As %String { Return ..InvalidStatic() } 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,! } } Code on GitHub.
go to post Eduard Lebedyuk · Jul 22, 2016 Here's the documentation detailing the process.Or do you have more specific questions?
go to post Eduard Lebedyuk · Jul 21, 2016 I tried a lot of open-sourced/generally available Source Control hooks for Studio/git integration and cache-tort-git offers the best wokflow as you don't need to switch from studio window for ~95% of source control usage cases.
go to post Eduard Lebedyuk · Jul 20, 2016 %ZEN.proxyObject works alright with first empty element in a list. Here's a sample: set json="{""Choices"":["""",10,20,30]}" do ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(json,,.obj) do ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(obj) { "Choices":["",10,20,30 ] } As for converting persistent objects to/from json, I would recommend first getting an example of json: set obj = ##class(Driver.Entity).%OpenId(id) do ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(obj) Would output json from object of Driver.Entity class. Then you can modify your json, so it would have the same structure. The important part is that json should contain _class property = Driver.Entity, this way %ConvertJSONToObject knows which class to convert json into.
go to post Eduard Lebedyuk · Jul 20, 2016 You can determine class based on a path by enforcing one standard of internal<->external name conversion. So you have two methods: ClassMethod GetExternalName(InternalName) As %String {} ClassMethod GetInternalName(ExternalName) As %String {} And the value of expressions: Write InternalName=..GetInternalName(..GetExternalName(InternalName)) Write ExternalName=..GetExternalName(..GetInternalName(ExternalName)) Is always 1 for any valid InternalName/ExternalName.
go to post Eduard Lebedyuk · Jul 19, 2016 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.
go to post Eduard Lebedyuk · Jul 19, 2016 For every query (which can be a simple SQL query or a custom class query, here’s my post about them and their uses) QueryFunc method gets generated: ClassMethod QueryFunc(Arg1, Arg2) As %SQL.StatementResult which returns a %SQL.StatementResult used to iterate over the query. For example your Display query for LastName.BasicClassQuery class can be called from object context with this code: Set ResultSet=##class(LastName.BasicClassQuery).DisplayFunc() While ResultSet.%Next() { Write ResultSet.Name,! }