go to post Eduard Lebedyuk · Dec 3, 2020 I run tests programmatically like this: ClassMethod runtest() As %Status { set ^UnitTestRoot = basedir set sc = ##class(%UnitTest.Manager).RunTest(testdir, "/nodelete") quit sc } ClassMethod isLastTestOk() As %Boolean { set in = ##class(%UnitTest.Result.TestInstance).%OpenId(^UnitTest.Result) for i=1:1:in.TestSuites.Count() { #dim suite As %UnitTest.Result.TestSuite set suite = in.TestSuites.GetAt(i) return:suite.Status=0 $$$NO } quit $$$YES }
go to post Eduard Lebedyuk · Nov 30, 2020 The format is stable, use XML tools for data import/export into persistent classes.
go to post Eduard Lebedyuk · Nov 28, 2020 To be honest despite about my 7+ years of experience in exposing class methods as sql procedures I've yet to write a name of a resulting sql procedure correctly. The trick I use is to open the list of procedures in SMP: In this list I search for an already existing procedure with the same nesting level, copy it and change identifiers to my values. That's how I wrote your query. First I copied: %Atelier_v1_Utils.Extension_AfterUserAction Then replaced %Atelier_v1_Utils with com_xyz_utils Finally replaced Extension_AfterUserAction with Users_getRole
go to post Eduard Lebedyuk · Nov 27, 2020 Try SELECT id, com_xyz_utils.Users_getRole(id) FROM users.users Note that package is underscored.
go to post Eduard Lebedyuk · Nov 27, 2020 Can you share some technical details? One of the projects: 1 Mirrored Data server 4 Non-mirrored App Servers They run Apache web servers.
go to post Eduard Lebedyuk · Nov 27, 2020 I recommend InterSystems IRIS REST API backend with any js framework frontend. 10 000 simulatenous clients are easily achievable. I know of InterSystems IRIS based applications in productions with even higher number of concurrent users.
go to post Eduard Lebedyuk · Nov 24, 2020 I encounter this issue fairly often, but I need not a complete documentaiton but rather Interoperability production documentation. As all the class info is also available as a %Dictionary package I just query it and generate XLSX. Here are some queries to get started (but they usually need to be adjusted on per-project basis). Also queries should be rewritten to use SubclassOf proc instead of the current matching. Also I'm not sure why I don't pass filestream directly. That also needs to be fixed. Queries /// Generate docs Class Utils.Doc { /// Generate Docs Tables /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"defaultSettings")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"productionClasses")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"productionSystemClasses")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"productionSystemClassesSettings")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"productionClassesSettings")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"productionItemsSettingsCall")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"productionItems")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"modelClasses")) /// w $system.Status.DisplayError(##class(Utils.Doc).generate(,"modelPropeties")) ClassMethod generate(filename As %String = {##class(%File).TempFilename("xlsx")}, query As %String, args...) As %Status { #dim sc As %Status = $$$OK #dim stream As %Stream.TmpCharacter = ##class(%Stream.TmpCharacter).%New() set sql = ..getSQL(query) set sc = ##class(util.XLSX).generateStreamFromSQL(.stream, sql, args...) quit:$$$ISERR(sc) sc set file = ##class(%FileCharacterStream).%New() set:$p(filename,".",*)'="xlsx" filename = filename _".xlsx" set file.Filename = filename set sc = file.CopyFrom(.stream) quit:$$$ISERR(sc) set sc = file.%Save() quit sc } ClassMethod getSQL(name) As %String { #dim sc As %Status = $$$OK set class = $case($l(name, ":"), 2:$p(name, ":"), :$classname()) set queryName = $p(name, ":", *) if ##class(%Dictionary.QueryDefinition).IDKEYExists(class, queryName) { set query = ##class(%Dictionary.QueryDefinition).IDKEYOpen(class, queryName,,.sc) throw:$$$ISERR(sc) ##class(%Exception.StatusException).CreateFromStatus(sc) set sql = query.SqlQuery } elseif ##class(%Dictionary.XDataDefinition).IDKEYExists(class, queryName) { #dim stream As %Stream.Object = ##class(isc.util.XmlUtils).getClassXData(class, queryName) set sql = stream.Read($$$MaxLocalLength) } else { throw ##class(%Exception.StatusException).CreateFromStatus($$$ERROR($$$GeneralError, $$$FormatText("Class %1 does not have Query or XData with name %2", class, queryName))) } set:(removeNL = $$$YES) sql = $replace(sql, $$$NL, " ") return sql } /// Generic settings for all Interoperability BH Query defaultSettings() As %Query { SELECT prop.name Setting, TRIM('"' FROM MAX(prop.InitialExpression)) "Default", LIST(prop.parent) Classes, MAX(prop.Description) Descrition FROM %Dictionary.PropertyDefinition prop JOIN %Dictionary.CompiledParameter par ON par.parent = prop.parent AND par.Name = 'SETTINGS' JOIN %Dictionary.CompiledClass cls ON prop.parent = cls.Name WHERE (cls.Super LIKE '%Ens.Host%' OR cls.Name = 'Ens.Host' OR cls.Name = 'Ens.BusinessProcessBPL') AND par."_Default" LIKE '%' || prop.Name || '%' GROUP BY prop.Name ORDER BY 1 } /// Production BHs Query productionClasses() As %Query { SELECT Name Class, Description Descrition FROM %Dictionary.CompiledClass cls WHERE Name LIKE 'production.%' AND Super In ('Ens.BusinessProcessBPL', 'Ens.BusinessService', 'Ens.BusinessOperation', 'Ens.BusinessProcess') ORDER BY 1 } /// System BHs Query productionSystemClasses() As %Query { SELECT Name Class, Description Descrition FROM %Dictionary.CompiledClass cls WHERE Name In ('util.SQLInboundAdapter', 'EnsLib.SQL.InboundAdapter', 'EnsLib.JavaGateway.Service', 'EnsLib.Workflow.Operation', 'Ens.InboundAdapter') ORDER BY 1 } /// System settings for BHs Query productionSystemClassesSettings() As %Query { SELECT prop.parent Class, prop.name Setting, TRIM('"' FROM prop.InitialExpression) "Default", prop.Description Descrition FROM %Dictionary.PropertyDefinition prop JOIN %Dictionary.CompiledParameter par ON par.parent = prop.parent AND par.Name = 'SETTINGS' JOIN %Dictionary.CompiledClass cls ON prop.parent = cls.Name WHERE cls.Name IN ('util.SQLInboundAdapter', 'EnsLib.SQL.InboundAdapter', 'EnsLib.JavaGateway.Service', 'EnsLib.Workflow.Operation', 'Ens.InboundAdapter') AND par."_Default" LIKE '%' || prop.Name || '%' ORDER BY 1,2 } /// BHs Settings Query productionClassesSettings(production) As %Query { SELECT prop.parent Class, prop.name Setting, TRIM('"' FROM prop.InitialExpression) "Default", prop.Description Descrition FROM %Dictionary.PropertyDefinition prop JOIN %Dictionary.CompiledParameter par ON par.parent = prop.parent AND par.Name = 'SETTINGS' JOIN %Dictionary.CompiledClass cls ON prop.parent = cls.Name WHERE cls.Name LIKE :production || '.%' and par."_Default" LIKE '%' || prop.Name || '%' ORDER BY 1,2 } /// Production BH Query productionItems(production) As %Query { SELECT Name Элемент, ClassName Class /*Comment Comment*/ FROM Ens_Config.Item WHERE Production = :production } /// Get settings for production Query productionItemsSettingsCall(production) As %Query { SELECT * FROM util.productionItemsSettings(:production) } /// Get settings for production Query productionItemsSettings(production As %String) As %Query(CONTAINID = 0, ROWSPEC = "Элемент:%String,Setting:%String,Цель:%String,Значение:%String") [ SqlName = productionItemsSettings, SqlProc ] { } ClassMethod productionItemsSettingsExecute(ByRef qHandle As %Binary, production As %String) As %Status { set obj = ##class(Ens.Config.Production).%OpenId(production,,.sc) quit:$$$ISERR(sc) sc do ..clearProductionItems(.obj) set qHandle("production") = obj set qHandle("item") = 1 set qHandle("itemCount") = qHandle("production").Items.Count() set qHandle("setting") = 1 set qHandle("settingCount") = qHandle("production").Items.GetAt(qHandle("item")).Settings.Count() quit sc } ClassMethod productionItemsSettingsFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = productionItemsSettingsExecute ] { #dim sc As %Status = $$$OK #dim item As Ens.Config.Item = qHandle("production").Items.GetAt(qHandle("item")) #dim setting As Ens.Config.Setting = item.Settings.GetAt(qHandle("setting")) set AtEnd = 0 set Row = $lb(item.Name, setting.Name, setting.Target, setting.Value) if qHandle("setting")<qHandle("settingCount") { set qHandle("setting") = qHandle("setting") + 1 } else { if qHandle("item")<qHandle("itemCount") { set qHandle("item") = qHandle("item") + 1 set qHandle("setting") = 1 set qHandle("settingCount") = qHandle("production").Items.GetAt(qHandle("item")).Settings.Count() } else { set AtEnd = 1 } } quit sc } /// Remove setting-less hosts ClassMethod clearProductionItems(ByRef production As Ens.Config.Production) { #dim item As Ens.Config.Item for i = production.Items.Count():-1:1 { set item = production.Items.GetAt(i) do:item.Settings.Count()=0 production.Items.RemoveAt(i) } } ClassMethod productionItemsSettingsClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = productionItemsSettingsFetch ] { kill qHandle quit $$$OK } /// Data model Query modelClasses() As %Query { SELECT Name Class, Description Descrition FROM %Dictionary.ClassDefinition WHERE Name LIKE 'model.%' AND GeneratedBy IS NULL -- AND Name NOT LIKE 'model.ref.%' } /// Data model properties Query modelPropeties() As %Query { SELECT cls.Name Class, prop.Name Свойство, prop.Type Тип, prop.Description Descrition FROM %Dictionary.ClassDefinition cls JOIN %Dictionary.PropertyDefinition prop ON cls.Name = prop.parent WHERE cls.Name LIKE 'model.%' AND cls.Name NOT LIKE 'model.ref.%' } }
go to post Eduard Lebedyuk · Nov 24, 2020 $zf functions (3-6 to be precise) cannot call arbitrary libraries but only InterSystems IRIS callout libraries. You need to write a C library which is an InterSystems IRIS callout library and which calls the dll you need. Here's documentation on that. And here's a sample callout library. Another approach would be using the CNA community project to call your library. CNA provides an interface for using native C-compatible shared libraries.
go to post Eduard Lebedyuk · Nov 17, 2020 Moved to Kitty from Putty a few years ago and it's way better for me.
go to post Eduard Lebedyuk · Nov 17, 2020 Check: Using the FTP Inbound Adapter Using the File Inbound Adapter
go to post Eduard Lebedyuk · Nov 15, 2020 Looks like a user permissions issue. question: which user does the Cache-terminal login as, is this different to the win10-services cache.exe settings. Yes, the terminal works under your OS user, Cache (and InterSystems IRIS) background jobs work under system account user (you can check services - Cache to see the user). You need to give permissions to access the share to system account user.
go to post Eduard Lebedyuk · Nov 13, 2020 As I said use object access instead. I have written a code sample which can be used with Native API for Python (although the first part with directory creation should probably just be called from PYTHON as is if you're on a same machine). Locals are not supported by Native API for Python.
go to post Eduard Lebedyuk · Nov 13, 2020 You can either 1. You can use object access from Python so this code can be invoked via Native API for Python: Set name = "ABC" Set dir = ##class(%File).SubDirectoryName(##class(%File).ManagerDirectory(), name, 1) Set sc = ##class(%File).CreateDirectory(dir) Write $SYSTEM.Status.GetErrorText(sc) Set db=##Class(SYS.Database).%New() Set db.Directory = dir Set sc = db.%Save() Write $SYSTEM.Status.GetErrorText(sc) Set dbConfig=##Class(Config.Databases).%New() Set dbConfig.Directory = dir Set dbConfig.Name = name Set sc = dbConfig.%Save() Write $SYSTEM.Status.GetErrorText(sc) 2. Use SQL via xDBC connection (CREATE DATABASE).
go to post Eduard Lebedyuk · Nov 13, 2020 1. Use Visual Trace to see message processing times. You can also query this information via SQL (Ens.MessageHeader table). 2. Add $$$TRACE events. The best time counter is $zh. They also can be queried via SQL (Ens_Util.Log table).
go to post Eduard Lebedyuk · Nov 13, 2020 There's a lot of different searches available in InterSystems IRIS. Can you show an example search you want explained?
go to post Eduard Lebedyuk · Nov 12, 2020 Any value could be displayed, TEST and so on are just presets.