accéder à la publication Sylvain Guilbaud · Jan 2 @Eduard Lebedyuk précise : L'idée d'un ensemble de résultats défilants est d'appeler Save/OpenId - et l'ensemble de résultats continuera automatiquement sur une ligne suivante. Vous n'avez donc pas besoin de gérer les indices avant/arrière : Un exemple ici Class User.Pagination { /// do ##class(User.Pagination).Time("NoSave") /// do ##class(User.Pagination).Time("Save") ClassMethod Time(method = "Save") { set start = $zh do $classmethod(,method) set end = $zh write $$$FormatText("%1 took %2 sec", method, $fnumber(end-start,"",4)) } /// do ##class(User.Pagination).NoSave() ClassMethod NoSave() { do { do $i(i) set obj = ..getPersonsPage(20,i) //w obj.%ToJSON(),!,! } while (obj.toIndex < obj.resultSetTotal) } /// do ##class(User.Pagination).Save() ClassMethod Save() { do { set obj = ..getPersonsPageSave(20,.id) //w obj.%ToJSON(),!,! } while (id'=-1) } ClassMethod getPersonsPage(pageSize As %String = 20, pageIndex As %String = 1) As %DynamicObject { #dim sc As %Status = $$$OK #dim rs As %ScrollableResultSet set sc = ..getRS(,.rs) quit:$$$ISERR(sc) {"msg": ($System.Status.GetErrorText(sc))} set vFrom = ((pageIndex -1 ) * pageSize) set vTo = vFrom + (pageSize-1) do rs.CurrRowSet(vFrom) set results = [] set:(pageSize >= rs.Count()) pageSize = rs.Count() set i = 0 while rs.%Next() && $i(i) { quit:(i>pageSize) do results.%Push({ "index": (i), "pid": (rs.%Get("ID")), "ssn" : (rs.%Get("SSN")), "age": (rs.%Get("Age"))}) //do results.%Push(+rs.%Get("ID")) } set out = { "pageSize":(pageSize), "pageIndex":(pageIndex), "fromIndex":(vFrom + 1), "toIndex":(vFrom+i), "resultSetTotal":(rs.Count()), "pageRecords":(i), "pages":($NORMALIZE((rs.Count()/pageSize),0)), "resultSet":(results) } return out } ClassMethod getRS(id As %Integer, Output rs As %ScrollableResultSet) As %Status { #dim sc As %Status = $$$OK if '$d(id) { set sql = "SELECT ID, SSN, Age FROM Sample.Person" set rs=##class(%ScrollableResultSet).%New("%DynamicQuery:SQL") set sc = rs.Prepare(sql) quit:$$$ISERR(sc) sc set sc = rs.Execute() quit:$$$ISERR(sc) sc quit:(rs.Count()=0) $$$ERROR($$$GeneralError, "No results") } else { set rs=##class(%ScrollableResultSet).%OpenId(id) } quit sc } ClassMethod getPersonsPageSave(pageSize As %String = 20, ByRef id As %Integer) As %DynamicObject { #dim sc As %Status = $$$OK #dim rs As %ScrollableResultSet set sc = ..getRS(.id,.rs) quit:$$$ISERR(sc) {"msg": ($System.Status.GetErrorText(sc))} set results = [] set:(pageSize >= rs.Count()) pageSize = rs.Count() set i = 0 set notAtEnd = rs.%Next() while notAtEnd && $i(i) { do results.%Push({ "index": (i), "pid": (rs.%Get("ID")), "ssn" : (rs.%Get("SSN")), "age": (rs.%Get("Age"))}) //do results.%Push(+rs.%Get("ID")) quit:(i>=pageSize) set notAtEnd = rs.%Next() } if notAtEnd { do rs.%Save() Set id=rs.%Id() } else { do rs.%DeleteId(id) set id = -1 } set out = { "pageSize":(pageSize), "resultSetTotal":(rs.Count()), "pageRecords":(i), "pages":($NORMALIZE((rs.Count()/pageSize),0)), "resultSet":(results) } kill rs return out } } C'est également environ 3 fois plus rapide puisque la requête n'est exécutée qu'une seule fois : do ##class(User.Pagination).Time("Save") Save took 0,0048 sec do ##class(User.Pagination).Time("NoSave") NoSave took 0,0143 sec
accéder à la publication Sylvain Guilbaud · Jan 2 @Guillaume Rongier ajoute : Bonjour Rubén, Une autre proposition sur IRIS 2021.1+ peut être celle-ci avec l'utilisation de la fonction nouvelle fenêtre (OVER) : ClassMethod getPersonsPagWindow(iAge As %Integer, sortField As %String = 1, sortOrder As %String = 2, pageSize As %String = 20, pageIndex As %String = 1) As %DynamicObject { set out = [] set vFrom = ((pageIndex -1 ) * pageSize)+1 set vTo = vFrom + (pageSize-1) set sql = "SELECT * "_ "FROM ( SELECT persons.* "_ " , ROW_NUMBER() OVER (ORDER By "_sortField_" "_ $CASE(sortOrder,1:"ASC",2:"DESC",:"ASC")_ " ) rn "_ " FROM Sample.Person persons where Age > ? "_ " ) tmp "_ "WHERE rn between "_vFrom_" and "_vTo_" "_ "ORDER By "_sortField_" "_ $CASE(sortOrder,1:"ASC",2:"DESC",:"ASC") Set rs=##class(%ResultSet).%New("%DynamicQuery:SQL") set sc = rs.Prepare(sql) set sc = rs.Execute(iAge) If $$$ISERR(sc) Do DisplayError^%apiOBJ(sc) Quit while rs.%Next() { Do out.%Push({ "pid": (rs.%Get("ID")), "ssn" : (rs.%Get("SSN")), "lastname" : (rs.%Get("LastName")) , "givenname": (rs.%Get("GivenName")), "secondaryname": (rs.%Get("SecondaryName")) , "gender": (rs.%Get("Gender")), "age": (rs.%Get("Age") ) }) } set outJson = [] Do outJson.%Push({ "pageSize":(pageSize), "pageIndex":(pageIndex), "fromIndex":(vFrom), "toIndex":(vTo), "resultSet":(out) }) return outJson } Je compare les deux solutions sur un dataset de 100 000 lignes sans index avec un résultat de 20 éléments en page 1 et voici les résultats : "getPersonsPag timed : 1,647 secondes" "getPersonsPagWindow timed : 0,247 secondes" Je suppose que la fonction window est plus rapide car vous n'avez pas besoin de récupérer toutes les données de manière globale avant la pagination.
accéder à la publication Sylvain Guilbaud · Déc 27, 2023 Une fois obtenu le fichier Excel, il est possible de le convertir en CSV puis en PDF en utilisant les librairies pandas et csv2pdf ClassMethod toPDF(file As %String) As %Status [ Language = python ] { import pandas as pd from csv2pdf import convert PATH = '/home/irisowner/dev/data/' PATH_TO_XLSX = PATH+file+'.xlsx' PATH_TO_CSV = PATH+file+'.csv' PATH_TO_PDF = PATH+file+'.pdf' read_file = pd.read_excel (PATH_TO_XLSX) read_file.to_csv (PATH_TO_CSV, index = None, header=True) convert(PATH_TO_CSV , PATH_TO_PDF) }
accéder à la publication Sylvain Guilbaud · Déc 27, 2023 Bonjour @Pierre LaFay en m'inspirant des liens proposés par @Guillaume Rongier tu trouveras ci-dessous et en ligne un exemple de génération de feuille Excel à partir de openpyxl Code /// d ##class(apptools.python.xlsx).test() Class apptools.python.xlsx { Parameter DATADIRECTORY = "/home/irisowner/dev/data/"; /// d ##class(apptools.python.xlsx).test() ClassMethod test(name As %String = "titanicTest") As %Status { set name=name_$INCREMENT(^RunAppTest(name)) set sql="select * FROM dc_demo.titanic" #; set sql="select name,sex,age FROM dc_demo.titanic" set gn="^||tmp",format=",n,n,n,n,s5,s5,s40,s5,s50" set format("freeze")="B3" ;freeze set format("title")="Title "_sql set format("sheetname")="test" #; do ##class(apptools.core.sys).SaveSQL(sql,gn) set exec="##class(apptools.python.xlsx).MarkRed(.%AppLogInfoVal, .%AppLogInfoCol, .%AppLogInfoHead, .%AppLogInfoTemp)" #; do ##class(apptools.python.xlsx).gn2xlsx(gn,.format,..#DATADIRECTORY_"___gn2xlsx*.xlsx","Title "_sql,,,,exec) set format("freeze")="B4" ;freeze do ##class(apptools.python.xlsx).sql2xlsx(sql,.format,..#DATADIRECTORY_name_".xlsx") do ..toPDF(name) return $$$OK } ClassMethod sql2xlsx(sql, format = "", file As %String = "/home/irisowner/dev/data/sample-py-*.xlsx", title = "") { set st=$$$OK set statement = ##CLASS(%SQL.Statement).%New() set status=statement.%Prepare(sql) if $$$ISERR(status) {write "%Prepare failed:" do $SYSTEM.Status.DisplayError(status) quit} set rset=statement.%Execute() if (rset.%SQLCODE '= 0) {write "%Execute failed:", !, "SQLCODE ", rset.%SQLCODE, ": ", rset.%Message quit} ;prepare XLSX try { set openpyxl = ##class(%SYS.Python).Import("openpyxl") } catch err { do ..InstallPy("openpyxl") set openpyxl = ##class(%SYS.Python).Import("openpyxl") } set wb = openpyxl.Workbook() #; grab the active worksheet set ws = wb.active set ws.title = $select($D(format("sheetname"),ds):ds,1:"sheetname") set pybuiltins = $system.Python.Import("builtins") set pycols = pybuiltins.list() do pycols.append(" ") do ws.append(pycols) set pycols = pybuiltins.list() set (count)=0 set ColCount=statement.%Metadata.columns.Count() for i=1:1:ColCount { do pycols.append(statement.%Metadata.columns.GetAt(i).colName) set col=openpyxl.utils."get_column_letter"(i) } do ws.append(pycols) while (rset.%Next()) { set count=count+1 set pyrows = pybuiltins.list() for ii=1:1:ColCount { set val=..CleanCtrl(rset.%GetData(ii)) if $e($P(format,",",ii),1)="d" { //date set val=..ToPyDate(val) } elseif $e($P(format,",",ii),1,2)="dt" { //datetime set val=..ToPyDateTime(val) } elseif $e($P(format,",",ii),1)="n" { //number set val=+val } do pyrows.append(val) } do ws.append(pyrows) } ;} if $g(format("freeze"))'="" { ; set builtins = $system.Python.Import("builtins") zwrite builtins.type(ws) zwrite builtins.dir(wb) set ws."freeze_panes" = pybuiltins.str(format("freeze")) ;format("freeze") ;set ws."freeze_panes" = "B2" ;format("freeze") } else { set ws."freeze_panes" = pybuiltins.str("B2") ;default } if file["*" set file=$replace(file,"*","-"_$zd($h,3)_"_"_$tr($zt($p($h,",",2),1),":")) write !,"Save into "_file_" rows: "_count do wb.save(file) return $GET(count) } ClassMethod toPDF(file As %String) As %Status [ Language = python ] { import pandas as pd from csv2pdf import convert PATH = '/home/irisowner/dev/data/' PATH_TO_XLSX = PATH+file+'.xlsx' PATH_TO_CSV = PATH+file+'.csv' PATH_TO_PDF = PATH+file+'.pdf' read_file = pd.read_excel (PATH_TO_XLSX) read_file.to_csv (PATH_TO_CSV, index = None, header=True) convert(PATH_TO_CSV , PATH_TO_PDF) } /// set gn="^||tmp",format="n,s150,,,,,,,,d," /// set format("freeze")="B5" ;freeze /// d ##class(apptools.core.sys).SaveSQL("select * from apptools_core.Log order by id desc",gn) /// d ##class(apptools.python.xlsx).gn2xlsx(gn,.format,"/iris-backup/temp/test*.xlsx","Test") /// Example coloring a column values if is not null /// set exec="##class(apptools.python.xlsx).MarkRed(.%AppLogInfoVal, %AppLogInfoCol, %AppLogInfoHead, .%AppLogInfoTemp)" ClassMethod MarkRed(Val, Col, Head, openpyxl) { s res=Val if $g(Head) { if res.value="DispatchClass" set Col("DispatchClass",Col)="" } else { if $Data(Col("DispatchClass",Col)) { if res.value'="" { ;set argsfill = {"start_color":"D3D3D3", "end_color":"D3D3D3", "fill_type":"solid"} ;set fill = openpyxl.styles.PatternFill(argsfill...) set argsfont = {"color":"DC143C", "bold":true, "italic":false, "size":11} ;color Crimson set font = openpyxl.styles.Font(argsfont...) ;set res.value=$FN(res.value,"",2) ;set res.fill=fill set res.font=font } } } q res } /// do ##class(apptools.python.xlsx).InstallPy("openpyxl") ClassMethod InstallPy(lib) { // depricated ;set sc = ##class(%SYS.Python).Install("openpyxl") set cmd="pip3 install --target /usr/irissys/mgr/python/ "_lib if $zversion(1)'=3 { set tMgrDir = $System.Util.ManagerDirectory() set tBinDir = $System.Util.BinaryDirectory()_"irispip.exe" set cmd=tBinDir_" install --target "_tMgrDir_"python "_lib } set st=##class(%ZPM.PackageManager.Developer.Utils).RunCommandViaZF(cmd,.tLog,.tErr) quit $$$OK } /// Date YYYY-MM-DD HH:MM:SS to Python dt.datetime ClassMethod ToPyDateTime(val, ByRef dt) { quit:'val val if val["." set val=$p(val,".",3)_"-"_$p(val,".",2)_"-"_$p(val,".",1) // format YYYY-MM-DD if val'["-" set val=$zd(+val,3) // $h format set dt = ##class(%SYS.Python).Import("datetime") set val=dt.datetime(+$p(val,"-",1), +$p(val,"-",2), +$p($p(val,"-",3)," "),+$p($p(val,":",1)," ",2),+$p($p(val,":",2)," ",2),+$p($p(val,":",3)," ",2)) quit val } /// Date YYYY-MM-DD to Python dt.date ClassMethod ToPyDate(val, ByRef dt) { quit:'val val if val["." set val=$p(val,".",3)_"-"_$p(val,".",2)_"-"_$p(val,".",1) // format YYYY-MM-DD if val'["-" w 111_val_111 set val=$zd(+val,3) // $h format set dt = ##class(%SYS.Python).Import("datetime") set val=dt.date(+$p(val,"-",1), +$p(val,"-",2), +$p($p(val,"-",3)," ")) quit val } ClassMethod CleanCtrl(val) { quit $zstrip(val,"*C") } }
accéder à la publication Sylvain Guilbaud · Déc 27, 2023 2023 a été une très belle année pour Developer Community, qui a vu le nombre de ses membres s'accroître fortement, dans toutes ses pays, avec une augmentation de la qualité des articles, des commentaires et des applications sur Open Exchange.2024 sera encore plus riche en contenus et en solutions
accéder à la publication Sylvain Guilbaud · Déc 18, 2023 Exemple de classe utilisant un index IDKEY Test IRISAPP>w ##class(data.centre).test() ^data.centreD("departement",83)=10 ^data.centreD("departement",83,1)=$lb("","The industry leader in just-in-time seven-sigma Internet content for social networks.") ^data.centreD("departement",83,2)=$lb("","On-line distributors of open distributed Internet connectivity for capital markets.") ^data.centreD("departement",83,3)=$lb("","Developers of cutting-edge HTML5 XML instruments for our long-term clients.") ^data.centreD("departement",83,4)=$lb("","Building shareholder value by delivering advanced financial application development media for industry and academia.") ^data.centreD("departement",83,5)=$lb("","Providers of breakthrough satellite-based advanced connectivity for industry and academia.") ^data.centreD("departement",83,6)=$lb("","Resellers of cloud-based seven-sigma database connectivity for the enterprise.") ^data.centreD("departement",83,7)=$lb("","Developers of dynamic object-oriented graphical services for social networks.") ^data.centreD("departement",83,8)=$lb("","Developers of high-performance nano-advanced productivity tools for the Fortune 50.") ^data.centreD("departement",83,9)=$lb("","Specializing in the development and manufacturing of breakthrough wireless forecasting marketing services for the enterprise.") ^data.centreD("departement",83,10)=$lb("","Enabling individuals and businesses to manage just-in-time big data Internet technologies for discriminating investors.") 1 IRISAPP>w ##class(data.centre).test(3) ^data.centreD("departement",83)=13 ^data.centreD("departement",83,1)=$lb("","The industry leader in just-in-time seven-sigma Internet content for social networks.") ^data.centreD("departement",83,2)=$lb("","On-line distributors of open distributed Internet connectivity for capital markets.") ^data.centreD("departement",83,3)=$lb("","Developers of cutting-edge HTML5 XML instruments for our long-term clients.") ^data.centreD("departement",83,4)=$lb("","Building shareholder value by delivering advanced financial application development media for industry and academia.") ^data.centreD("departement",83,5)=$lb("","Providers of breakthrough satellite-based advanced connectivity for industry and academia.") ^data.centreD("departement",83,6)=$lb("","Resellers of cloud-based seven-sigma database connectivity for the enterprise.") ^data.centreD("departement",83,7)=$lb("","Developers of dynamic object-oriented graphical services for social networks.") ^data.centreD("departement",83,8)=$lb("","Developers of high-performance nano-advanced productivity tools for the Fortune 50.") ^data.centreD("departement",83,9)=$lb("","Specializing in the development and manufacturing of breakthrough wireless forecasting marketing services for the enterprise.") ^data.centreD("departement",83,10)=$lb("","Enabling individuals and businesses to manage just-in-time big data Internet technologies for discriminating investors.") ^data.centreD("departement",83,11)=$lb("","On-line distributors of scalable predictive analytic XML gaming for our long-term clients.") ^data.centreD("departement",83,12)=$lb("","On-line distributors of interactive quantum advanced media for the pharmaceutical industry.") ^data.centreD("departement",83,13)=$lb("","Building shareholder value by delivering innovative distributed cold-fusion powered gaming for the Financial community.") 1 Class data.centre Extends %Persistent { /// Description Index IdKeyIndex On (APP, DD, NNN) [ IdKey ]; /// Nom de l'application utilisée par le centre Property APP As %String; /// n° du département du centre Property DD As %Integer; /// n° séquentiel dans le département Property NNN As %Integer; Property description As %String(MAXLEN = ""); ClassMethod create(APP As %String, DD As %Integer, description As %String) As %Status { set a = ..%New() set a.APP = APP set a.DD = DD set a.NNN = $INCREMENT(^data.centreD(APP,DD)) set a.description = description set sc = a.%Save() return sc } ClassMethod test(nb As %Integer = 10) As %Status { for i=1:1:nb { set sc = ..create("departement",83,##class(%PopulateUtils).Mission()) } zw ^data.centreD return sc } Storage Default { <Data name="centreDefaultData"> <Value name="1"> <Value>%%CLASSNAME</Value> </Value> <Value name="2"> <Value>description</Value> </Value> </Data> <DataLocation>^data.centreD</DataLocation> <DefaultData>centreDefaultData</DefaultData> <IdLocation>^data.centreD</IdLocation> <IndexLocation>^data.centreI</IndexLocation> <StreamLocation>^data.centreS</StreamLocation> <Type>%Storage.Persistent</Type> } }
accéder à la publication Sylvain Guilbaud · Déc 18, 2023 Dans ton cas, $INCREMENT te donnera une meilleure garantie de séquentialité, en évitant les sauts de numéros.
accéder à la publication Sylvain Guilbaud · Déc 18, 2023 Bonjour @Pierre LaFay tu peux aussi utiliser $SEQUENCE $SEQUENCE est spécifiquement destiné aux opérations d'incrémentation d'entiers impliquant plusieurs processus simultanés.
accéder à la publication Sylvain Guilbaud · Nov 3, 2023 NB: si tu rencontres d'autres erreurs, pense à les indiquer clairement dans les échanges afin qu'elles soient référencées ; cela permet de les retrouver plus facilement lors des recherches de pb similaires déjà rencontrés.
accéder à la publication Sylvain Guilbaud · Nov 3, 2023 Bonjour Moussa, comme vu ensemble cet après-midi, je t'invite à bien tracer chaque étape et à consulter cet échange autour de l'authentication OAuth 2.0 avec Microsoft Office 365. Bien à toi, Sylvain
accéder à la publication Sylvain Guilbaud · Oct 23, 2023 C'est effectivement un très beau premier jalon @Irène Mykhailova Merci de partager cette très encourageante information.à suivre 😍
accéder à la publication Sylvain Guilbaud · Sept 28, 2023 Bonjour @Jean-Charles Cano, Stream n'est pas une méthode mais une propriété ; aussi, tout devrait aller mieux après avoir remplacé cette ligne : set esc = ..Adapter.PutStream(fileName, pRequest.Stream()) par celle-ci : set esc = ..Adapter.PutStream(fileName, pRequest.Stream)
accéder à la publication Sylvain Guilbaud · Sept 26, 2023 Je suis bien d'accord @Iryna Mykhailova Le site InterSystems Learning étant déjà disponible en français, peut-être verrons-nous prochainement des contenus de plus en plus nombreux de formations dans la langue de Molière et de Prévert.
accéder à la publication Sylvain Guilbaud · Sept 26, 2023 Réponse de @Ashok Kumar Bonjour @Muhammad Waseem Vous pouvez peut-être essayer d'extraire la ressource patient du bundle ou l'utiliser si c'est déjà une ressource. Chargez la classe du modèle patient FHIR HS.FHIR.DTL.vR4.Model.Resource.Patient avec la ressource extraite. Ensuite, vous pouvez convertir la date de naissance et valider l'âge. Vous pouvez utiliser la même logique dans votre code DTL dans un processus FHIR entre le service FHIR (HS.FHIRServer.Interop.Service) et l'opération FHIR (HS.FHIRServer.Interop.Operation). ClassMethod VaidatePatientResource(patientResourceStreram As %Stream.Object) { #dim patient As HS.FHIR.DTL.vR4.Model.Resource.Patient try { set patient = ##class(HS.FHIR.DTL.vR4.Model.Resource.Patient).FromJSON(patientResourceStreram) Set age = $horolog - $ZdateH(patient.birthDate,3)\360 if age<18 $$$ThrowStatus($$$ERROR($$$GeneralError, "Age is less than 18")) } catch ex { w ex.DisplayString() } }
accéder à la publication Sylvain Guilbaud · Sept 25, 2023 15 applications de réelle qualité 😀 Merci à tous les participants pour leur implication et leurs idées.
accéder à la publication Sylvain Guilbaud · Sept 22, 2023 Bonjour @Julia Pertin peux-tu me donner plus de détails sur l'erreur rencontrée ? Vérifies-bien si tu recrées une production from scratch, en ajoutant service-process-operation, de conserver les noms les BS-BP-BO identiques aux noms des 3 classes EP.service.replication, EP.process.replication et EP.operation.replication, et qu'ils sont bien reliés entre eux.
accéder à la publication Sylvain Guilbaud · Sept 20, 2023 L'intérêt du Ens.StreamContainer est de dépasser la limite des 3,6Mo du type %String. Exemple d'une trace avec un flux json de 5,79 Mo (stream size: 6081494) pour 100000 enregistrements :
accéder à la publication Sylvain Guilbaud · Sept 20, 2023 Le code de la Business Opération : Class EP.operation.replication Extends Ens.BusinessOperation { Property Adapter As Ens.OutboundAdapter; Parameter ADAPTER = "Ens.OutboundAdapter"; Parameter INVOCATION = "Queue"; Method sync(pRequest As Ens.StreamContainer, Output pResponse As Ens.StringContainer) As %Status { set pResponse = ##class(Ens.StringContainer).%New() set json = [].%FromJSON(pRequest.Stream) set array = json.%GetIterator() while array.%GetNext(.key,.value) { $$$TRACE("Data:"_value.%ToJSON()) set a = ##class(data.client2).%New() set sc = a.%JSONImport(value) if 'sc { $$$LOGERROR("ERROR while importing:"_$system.Status.GetErrorText(sc)) } else { set sc = a.%Save() } } set pResponse.StringValue = key _" records inserted" return sc } XData MessageMap { <MapItems> <MapItem MessageType="Ens.StreamContainer"> <Method>sync</Method> </MapItem> </MapItems> } }
accéder à la publication Sylvain Guilbaud · Sept 20, 2023 Le code du Business Process Class EP.process.replication Extends Ens.BusinessProcess [ ClassType = persistent, ProcedureBlock ] { Property Server As %String [ InitialExpression = "host.docker.internal" ]; Property Port As %Integer [ InitialExpression = 12773 ]; Property classname As %String [ InitialExpression = "data.client" ]; Parameter SETTINGS = "Server:target,Port:target,classname:target"; Method OnRequest(pRequest As Ens.Request, Output pResponse As Ens.StringContainer) As %Status { set sc = $$$OK set tHttpRequest = ##class(%Net.HttpRequest).%New() set pContainer = ##class(Ens.StreamContainer).%New() set stream = ##class(%Stream.GlobalCharacter).%New() set tHttpRequest.Server = ..Server set tHttpRequest.Port = ..Port set location = "/common/list/" _ ..classname _ "/json" set tHttpRequest.ContentType = "application/json" set tHttpRequest.Timeout = 900 set tSC = tHttpRequest.Get(location) if $ISOBJECT(tHttpRequest.HttpResponse) { Set jsonObject = [].%FromJSON(tHttpRequest.HttpResponse.Data) Do jsonObject.%ToJSON(.stream) set pContainer.Stream = stream $$$TRACE("stream size:"_stream.Size) $$$TRACE("stream data:"_stream.Read(1000)) set sc = ..SendRequestSync("EP.operation.replication",pContainer,.pResponse) } return sc } Storage Default { <Data name="replicationDefaultData"> <Subscript>"replication"</Subscript> <Value name="1"> <Value>Server</Value> </Value> <Value name="2"> <Value>Port</Value> </Value> <Value name="3"> <Value>classname</Value> </Value> </Data> <DefaultData>replicationDefaultData</DefaultData> <Type>%Storage.Persistent</Type> } }
accéder à la publication Sylvain Guilbaud · Sept 20, 2023 Le code du Business Service : Class EP.service.replication Extends Ens.BusinessService { Property Adapter As Ens.InboundAdapter; Parameter ADAPTER = "Ens.InboundAdapter"; Property TargetConfigNames As %String(MAXLEN = 1000); Property sync As %Boolean [ InitialExpression = 1 ]; Parameter SETTINGS = "sync:Advanced,TargetConfigNames:Basic:selector?multiSelect=1&context={Ens.ContextSearch/ProductionItems?targets=1&productionName=@productionId}"; Method OnProcessInput(pInput As %RegisteredObject, Output pResponse As Ens.StringResponse) As %Status { set tSC = $$$OK for iTarget=1:1:$L(..TargetConfigNames, ",") { set tOneTarget=$ZStrip($P(..TargetConfigNames,",",iTarget),"<>W") Continue:""=tOneTarget $$$TRACE("The target '"_tOneTarget_"' will be called "_$SELECT(..sync=1:"synchronously",..sync=0:"synchronously")) if ..sync { set tSC1=..SendRequestSync(tOneTarget,pInput,.pResponse) Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1) } else { set tSC1=..SendRequestAsync(tOneTarget,pInput) Set:$$$ISERR(tSC1) tSC=$$$ADDSC(tSC,tSC1) } } return tSC } /// Return an array of connections for drawing lines on the config diagram ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item) { Do ##super(.pArray,pItem) If pItem.GetModifiedSetting("TargetConfigNames",.tValue) { For i=1:1:$L(tValue,",") { Set tOne=$ZStrip($P(tValue,",",i),"<>W") Continue:""=tOne Set pArray(tOne)="" } } } }