├── .gitattributes ├── .gitignore ├── .dockerignore ├── docker-compose.yml ├── .github └── workflows │ ├── objectscript-quality.yml │ └── build-push-gcr.yaml ├── irissession.sh ├── Dockerfile ├── .vscode └── settings.json ├── iris.script ├── src └── cls │ ├── BI │ ├── Model │ │ ├── KPIs │ │ │ ├── BPSystolic.cls │ │ │ ├── BPDiastolic.cls │ │ │ ├── Years.cls │ │ │ ├── DemoMDXAutoFilters.cls │ │ │ ├── DemoCrossjoin.cls │ │ │ ├── DemoSQL.cls │ │ │ ├── DemoInteroperability.cls │ │ │ ├── DemoMDX.cls │ │ │ ├── DemoTrendLines.cls │ │ │ ├── PluginDemo.cls │ │ │ ├── DemoDataChanges.cls │ │ │ └── BubbleChartDemo.cls │ │ ├── CompoundCube │ │ │ ├── CompoundCube.cls │ │ │ ├── CityRainfall.cls │ │ │ ├── Doctors.cls │ │ │ └── Patients.cls │ │ ├── SubjectAreas │ │ │ ├── AsthmaPatients.cls │ │ │ ├── YoungPatients.cls │ │ │ └── DemoMDX.cls │ │ ├── SampleListingGroup.cls │ │ ├── PatientsQuery.cls │ │ ├── CityCube.cls │ │ ├── RelCubes │ │ │ ├── RAllergies.cls │ │ │ ├── RCities.cls │ │ │ ├── RCityRainfall.cls │ │ │ ├── RDoctors.cls │ │ │ └── RPatients.cls │ │ ├── PatientsQueryCube.cls │ │ ├── RainfallCube.cls │ │ ├── ConnectorCube.cls │ │ ├── ConnectorExample.cls │ │ └── PortletDemo │ │ │ ├── ClockPortlet.cls │ │ │ └── svgClock.cls │ ├── Study │ │ ├── PatientDiagnosis.cls │ │ ├── PatientDiagnosis1.cls │ │ ├── PatientDiagnosis2.cls │ │ ├── PatientAllergy1.cls │ │ ├── AllergySeverity.cls │ │ ├── Allergen.cls │ │ ├── PatientAllergy.cls │ │ ├── City.cls │ │ ├── Profession.cls │ │ ├── CityRainfall.cls │ │ ├── Diagnosis.cls │ │ ├── PatientDetails.cls │ │ ├── PatientSet2.cls │ │ ├── PatientEncounter.cls │ │ └── Doctor.cls │ ├── Utils │ │ └── MDXAutoFiltersKPI.cls │ └── APISamples.cls │ └── HoleFoods │ ├── SubjectAreaAsia.cls │ ├── KPIYears.cls │ ├── Region.cls │ ├── CombinedCube.cls │ ├── Country.cls │ ├── Product.cls │ ├── KPIAction.cls │ ├── Outlet.cls │ ├── BudgetCube.cls │ ├── KPISQL.cls │ ├── Transaction.cls │ ├── KPISalesVsTarget.cls │ ├── KPICFO.cls │ └── Cube.cls ├── module.xml ├── LICENSE ├── Installer.cls ├── dev.md └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | ISC 3 | 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | .vscode/ 3 | .github/ 4 | buildsample/ 5 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | iris: 4 | build: 5 | context: . 6 | dockerfile: ${DOCKERFILE:-Dockerfile} 7 | command: --check-caps false 8 | restart: always 9 | ports: 10 | - 1972 11 | - 52773 12 | - 53773 13 | volumes: 14 | - ~/iris.key:/usr/irissys/mgr/iris.key 15 | - ./:/irisdev/app 16 | -------------------------------------------------------------------------------- /.github/workflows/objectscript-quality.yml: -------------------------------------------------------------------------------- 1 | name: objectscriptquality 2 | on: push 3 | 4 | jobs: 5 | linux: 6 | name: Linux build 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Execute ObjectScript Quality Analysis 11 | run: wget https://raw.githubusercontent.com/litesolutions/objectscriptquality-jenkins-integration/master/iris-community-hook.sh && sh ./iris-community-hook.sh 12 | 13 | -------------------------------------------------------------------------------- /irissession.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iris start $ISC_PACKAGE_INSTANCENAME quietly 4 | 5 | cat << EOF | iris session $ISC_PACKAGE_INSTANCENAME -U %SYS 6 | do ##class(%SYSTEM.Process).CurrentDirectory("$PWD") 7 | $@ 8 | if '\$Get(sc) do ##class(%SYSTEM.Process).Terminate(, 1) 9 | zn "%SYS" 10 | do ##class(SYS.Container).QuiesceForBundling() 11 | Do ##class(Security.Users).UnExpireUserPasswords("*") 12 | halt 13 | EOF 14 | 15 | exit=$? 16 | 17 | iris stop $ISC_PACKAGE_INSTANCENAME quietly 18 | 19 | exit $exit -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE=intersystemsdc/iris-community:latest 2 | FROM $IMAGE 3 | 4 | USER root 5 | WORKDIR /opt/irisapp 6 | RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp 7 | 8 | USER ${ISC_PACKAGE_MGRUSER} 9 | 10 | # copy files 11 | COPY Installer.cls . 12 | COPY src src 13 | COPY module.xml . 14 | COPY iris.script /tmp/iris.script 15 | 16 | # run iris and script 17 | RUN iris start IRIS \ 18 | && iris session IRIS < /tmp/iris.script \ 19 | && iris stop IRIS quietly 20 | 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | 4 | "Dockerfile*": "dockerfile", 5 | "iris.script": "objectscript" 6 | }, 7 | "objectscript.conn" :{ 8 | "ns": "IRISAPP", 9 | "active": false, 10 | "username": "_SYSTEM", 11 | "docker-compose": { 12 | "service": "iris", 13 | "internalPort": 52773 14 | }, 15 | "links": { 16 | "SAMPLES BI in ZEN": "http://localhost:${port}/csp/irisapp/_DeepSee.UserPortal.DashboardViewer.zen" 17 | } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /iris.script: -------------------------------------------------------------------------------- 1 | ; add a bit of standard docker comfort 2 | zn "%SYS" 3 | do ##class(Security.Users).UnExpireUserPasswords("*") 4 | ;; just a proposal 5 | ;; set user=##class(Security.Users).%OpenId("unknownuser") 6 | ;; do user.Roles.Insert("%All") 7 | 8 | ; run installer to create namespace 9 | do $SYSTEM.OBJ.Load("/opt/irisapp/Installer.cls", "ck") 10 | set sc = ##class(App.Installer).setup() 11 | 12 | zn "IRISAPP" 13 | zpm "install isc-dev" 14 | do ##class(dev.code).workdir("/irisdev/app/src") 15 | do EnableDeepSee^%SYS.cspServer("/csp/irisapp/") 16 | zpm "load /opt/irisapp/ -v -Dfolder=irisapp" 17 | 18 | halt 19 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/BPSystolic.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// 1-row hardcoded KPI for use in demonstrating ranges and thresholds in a *meter*. 3 | Class BI.Model.KPIs.BPSystolic Extends %DeepSee.KPI 4 | { 5 | 6 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 7 | { 8 | 11 | 12 | 13 | 14 | } 15 | 16 | Method %OnLoadKPI() As %Status 17 | { 18 | set ..%rangeLower=70 19 | set ..%thresholdLower=90 20 | set ..%thresholdUpper=120 21 | set ..%rangeUpper=190 22 | quit $$$OK 23 | } 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/BPDiastolic.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// 1-row hardcoded KPI for use in demonstrating ranges and thresholds in a *meter*. 3 | Class BI.Model.KPIs.BPDiastolic Extends %DeepSee.KPI 4 | { 5 | 6 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 7 | { 8 | 11 | 12 | 13 | 14 | } 15 | 16 | Method %OnLoadKPI() As %Status 17 | { 18 | set ..%rangeLower=40 19 | set ..%thresholdLower=60 20 | set ..%thresholdUpper=80 21 | set ..%rangeUpper=100 22 | quit $$$OK 23 | } 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/Years.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This KPI class provides the list of values for the 3 | /// Years pivot variable of the Patients cube. 4 | Class BI.Model.KPIs.Years Extends %DeepSee.KPI 5 | { 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 10 | { 11 | 16 | 17 | 20 | 21 | 22 | } 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/SubjectAreaAsia.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Example of a DeepSee Subject Area. 3 | /// This limits the data from the HOLEFOODS cube to data from ASIA only. 4 | Class HoleFoods.SubjectAreaAsia Extends %DeepSee.SubjectArea [ DependsOn = HoleFoods.Cube, ProcedureBlock ] 5 | { 6 | 7 | Parameter DOMAIN; 8 | 9 | /// SubjectArea definition from Architect. 10 | XData SubjectArea [ XMLNamespace = "http://www.intersystems.com/deepsee/subjectarea" ] 11 | { 12 | 13 | 14 | } 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/KPIYears.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This KPI class provides the list of values for the 3 | /// Years pivot variable of the HoleFoods cube. 4 | Class HoleFoods.KPIYears Extends %DeepSee.KPI 5 | { 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 10 | { 11 | 16 | 17 | 20 | 21 | 22 | } 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/cls/BI/Model/CompoundCube/CompoundCube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class defines a compound cube. 3 | /// To view the cube definition, open this class in Studio. 4 | Class BI.Model.CompoundCube.CompoundCube Extends %DeepSee.SubjectArea [ DependsOn = (BI.Model.CompoundCube.Patients, BI.Model.CompoundCube.Doctors, BI.Model.CompoundCube.CityRainfall) ] 5 | { 6 | 7 | /// This XData definition defines the SubjectArea. 8 | XData SubjectArea [ XMLNamespace = "http://www.intersystems.com/deepsee/subjectarea" ] 9 | { 10 | 12 | 13 | } 14 | 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/cls/BI/Model/SubjectAreas/AsthmaPatients.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a subject area based on the patients cube (BI.Model.PatientsCube). 4 | /// To view the subject area definition, open this class in Studio. 5 | /// 6 | Class BI.Model.SubjectAreas.AsthmaPatients Extends %DeepSee.SubjectArea [ DependsOn = BI.Model.PatientsCube ] 7 | { 8 | 9 | /// This XData definition defines the SubjectArea. 10 | XData SubjectArea [ XMLNamespace = "http://www.intersystems.com/deepsee/subjectarea" ] 11 | { 12 | 15 | 16 | } 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/cls/BI/Model/SubjectAreas/YoungPatients.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a subject area based on the patients cube (BI.Model.PatientsCube). 4 | /// To view the subject area definition, open this class in Studio. 5 | /// 6 | Class BI.Model.SubjectAreas.YoungPatients Extends %DeepSee.SubjectArea [ DependsOn = BI.Model.PatientsCube ] 7 | { 8 | 9 | /// This XData definition defines the SubjectArea. 10 | XData SubjectArea [ XMLNamespace = "http://www.intersystems.com/deepsee/subjectarea" ] 11 | { 12 | 15 | 16 | } 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/Region.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This specifies a geographic region within the HoleFoods demo. 3 | Class HoleFoods.Region Extends %Persistent 4 | { 5 | 6 | /// Name of this region. 7 | Property Name As %String(MAXLEN = 80); 8 | 9 | Storage Default 10 | { 11 | 12 | 13 | %%CLASSNAME 14 | 15 | 16 | Name 17 | 18 | 19 | ^HoleFoods.RegionD 20 | RegionDefaultData 21 | ^HoleFoods.RegionD 22 | ^HoleFoods.RegionI 23 | ^HoleFoods.RegionS 24 | %Storage.Persistent 25 | } 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientDiagnosis.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// See the comments for the Diagnoses property in BI.Study.Patient. 5 | Class BI.Study.PatientDiagnosis Extends %SerialObject 6 | { 7 | 8 | Property DiagnosisCode As %String; 9 | 10 | Property DiagnosedBy As BI.Study.Doctor; 11 | 12 | Storage Default 13 | { 14 | 15 | 16 | DiagnosisCode 17 | 18 | 19 | DiagnosedBy 20 | 21 | 22 | PatientDiagnosisState 23 | ^BI.Study.PatientDiagnosisS 24 | %Storage.Serial 25 | } 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/DemoMDXAutoFilters.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | Class BI.Model.KPIs.DemoMDXAutoFilters Extends BI.Utils.MDXAutoFiltersKPI 3 | { 4 | 5 | Parameter CUBE = "PATIENTS"; 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 10 | { 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | samples-bi 6 | 1.0.5 7 | Provides sample data for use with InterSystems IRIS Business Intelligence, as well as fully developed sample BI models and dashboards. 8 | module 9 | src 10 | 11 | 12 | 13 | 14 | 15 | ${namespace} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/CombinedCube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Sample of a DeepSee compound cube. 3 | /// This combine the HoleFoods Sales data with the Holefoods budget data into one model. 4 | Class HoleFoods.CombinedCube Extends %DeepSee.SubjectArea [ DependsOn = (HoleFoods.Cube, HoleFoods.BudgetCube), ProcedureBlock ] 5 | { 6 | 7 | Parameter DOMAIN; 8 | 9 | /// SubjectArea definition from Architect. 10 | XData SubjectArea [ XMLNamespace = "http://www.intersystems.com/deepsee/subjectarea" ] 11 | { 12 | 13 | 14 | 15 | 16 | 17 | } 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/Country.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This specifies the country within the HoleFoods demo. 3 | Class HoleFoods.Country Extends %Persistent 4 | { 5 | 6 | /// Region in which this country is located. 7 | Property Region As Region; 8 | 9 | /// Name of this country. 10 | Property Name As %String(MAXLEN = 90); 11 | 12 | Storage Default 13 | { 14 | 15 | 16 | %%CLASSNAME 17 | 18 | 19 | Region 20 | 21 | 22 | Name 23 | 24 | 25 | ^HoleFoods.CountryD 26 | CountryDefaultData 27 | ^HoleFoods.CountryD 28 | ^HoleFoods.CountryI 29 | ^HoleFoods.CountryS 30 | %Storage.Persistent 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 InterSystems Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/Product.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This represents a Product within the HoleFoods demo. 3 | Class HoleFoods.Product Extends %Persistent 4 | { 5 | 6 | Index KEY On SKU [ IdKey ]; 7 | 8 | /// Category of this product. 9 | Property Category As %String(MAXLEN = 100); 10 | 11 | /// Name of this product. 12 | Property Name As %String(MAXLEN = 120); 13 | 14 | /// SKU for this product. 15 | Property SKU As %String(MAXLEN = 22); 16 | 17 | /// List price for this product. 18 | Property Price As %Numeric(MINVAL = 0); 19 | 20 | Storage Default 21 | { 22 | 23 | 24 | %%CLASSNAME 25 | 26 | 27 | Category 28 | 29 | 30 | Name 31 | 32 | 33 | Price 34 | 35 | 36 | ^HoleFoods.ProductD 37 | ProductDefaultData 38 | ^HoleFoods.ProductD 39 | ^HoleFoods.ProductI 40 | ^HoleFoods.ProductS 41 | %Storage.Persistent 42 | } 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/KPIAction.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// KPI class used to supply Actions for the HOLEFOODS cube. 3 | /// This is a demonstration and does not actually do anything! 4 | Class HoleFoods.KPIAction Extends %DeepSee.KPI 5 | { 6 | 7 | /// This XData definition defines the KPI. 8 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 9 | { 10 | 13 | 14 | 15 | 16 | 17 | 18 | } 19 | 20 | /// This callback is invoked from a dashboard when an action defined by this dashboard is invoked. 21 | ClassMethod %OnDashboardAction(pAction As %String, pContext As %ZEN.proxyObject) As %Status 22 | { 23 | // pAction is the name of the action (as defined in the XML list). 24 | // pContext contains information from the client 25 | // and can be used to return information. 26 | 27 | // Value associated with current item in widget. 28 | set tSelectedValue = pContext.currValue 29 | 30 | if (pAction="ActionA") { 31 | // Go to a new page 32 | set pContext.command = "navigate:http://www.intersystems.com" 33 | } 34 | 35 | quit $$$OK 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientDiagnosis1.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// See the comments for the Diagnoses property in BI.Study.Patient. 5 | /// This table is populated only if you use the D option when running the 6 | /// GenerateData() method in BI.Populate. 7 | Class BI.Study.PatientDiagnosis1 Extends %Persistent 8 | { 9 | 10 | Relationship Patient As BI.Study.Patient [ Cardinality = parent, Inverse = DiagnosesAsChildren ]; 11 | 12 | Property DiagnosisCode As %String; 13 | 14 | Property DiagnosedBy As BI.Study.Doctor; 15 | 16 | Index PatientIndex On Patient; 17 | 18 | Storage Default 19 | { 20 | 21 | 22 | %%CLASSNAME 23 | 24 | 25 | DiagnosisCode 26 | 27 | 28 | DiagnosedBy 29 | 30 | 31 | {%%PARENT}("DiagnosesAsChildren") 32 | PatientDiagnosis1DefaultData 33 | ^BI.Study.PatientC("DiagnosesAsChildren") 34 | ^BI.Study.PatientDiagnosis1I 35 | ^BI.Study.PatientDiagnosis1S 36 | %Storage.Persistent 37 | } 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientDiagnosis2.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// See the comments for the Diagnoses property in BI.Study.Patient. 5 | /// This table is populated only if you use the D option when running the 6 | /// GenerateData() method in BI.Populate. 7 | Class BI.Study.PatientDiagnosis2 Extends %Persistent 8 | { 9 | 10 | Relationship Patient As BI.Study.Patient [ Cardinality = one, Inverse = DiagnosesAsMany ]; 11 | 12 | Property DiagnosisCode As %String; 13 | 14 | Property DiagnosedBy As BI.Study.Doctor; 15 | 16 | Index PatientIndex On Patient; 17 | 18 | Storage Default 19 | { 20 | 21 | 22 | %%CLASSNAME 23 | 24 | 25 | Patient 26 | 27 | 28 | DiagnosisCode 29 | 30 | 31 | DiagnosedBy 32 | 33 | 34 | ^BI.Study.PatientDiagnosis2D 35 | PatientDiagnosis2DefaultData 36 | ^BI.Study.PatientDiagnosis2D 37 | ^BI.Study.PatientDiagnosis2I 38 | ^BI.Study.PatientDiagnosis2S 39 | %Storage.Persistent 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/Outlet.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This represents a Sales Outlet for the HoleFoods demo. 3 | Class HoleFoods.Outlet Extends %Persistent 4 | { 5 | 6 | /// Country in which this city is located. 7 | Property Country As Country; 8 | 9 | /// City name of this location. 10 | Property City As %String(MAXLEN = 100); 11 | 12 | /// Population of this city. 13 | Property Population As %Integer(MINVAL = 0); 14 | 15 | /// Type of outlet: "retail", "web", etc. 16 | Property Type As %String(MAXLEN = 50); 17 | 18 | /// Latitude of this location. 19 | Property Latitude As %Double; 20 | 21 | /// Longitude of this location. 22 | Property Longitude As %Double; 23 | 24 | Storage Default 25 | { 26 | 27 | 28 | %%CLASSNAME 29 | 30 | 31 | Country 32 | 33 | 34 | City 35 | 36 | 37 | Population 38 | 39 | 40 | Type 41 | 42 | 43 | Latitude 44 | 45 | 46 | Longitude 47 | 48 | 49 | ^HoleFoods.OutletD 50 | OutletDefaultData 51 | ^HoleFoods.OutletD 52 | ^HoleFoods.OutletI 53 | ^HoleFoods.OutletS 54 | %Storage.Persistent 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/cls/BI/Model/SampleListingGroup.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class defines a listing group for the BI Patients sample. 3 | /// To see the definition of this listing group, use the BI > Tools > Listing Group Manager menu option 4 | /// or open this class in Studio. 5 | Class BI.Model.SampleListingGroup Extends %DeepSee.ListingGroupDefinition [ DependsOn = (BI.Model.PatientsCube, BI.Model.RelCubes.RPatients, BI.Model.SubjectAreas.AsthmaPatients, BI.Model.SubjectAreas.YoungPatients), Not ProcedureBlock ] 6 | { 7 | 8 | /// Need this because we have another listing group class with the same short class name. 9 | /// We use the XMLTYPE parameter to make sure these two classes project differently to XML. 10 | Parameter XMLTYPE = "PatientsSampleListingGroup"; 11 | 12 | Parameter DOMAIN = "PATIENTSAMPLE"; 13 | 14 | XData Listings [ XMLNamespace = "http://www.intersystems.com/deepsee/listinggroup" ] 15 | { 16 | 17 | 18 | 19 | 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/cls/BI/Model/PatientsQuery.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This Data Connector uses a UNION query that combines the main patient table with 3 | /// the "extra" patient set (BI.Study.PatientSet2). 4 | Class BI.Model.PatientsQuery Extends %DeepSee.DataConnector 5 | { 6 | 7 | XData SourceQuery [ XMLNamespace = "http://www.intersystems.com/deepsee/connector/query" ] 8 | { 9 | 10 | SELECT %ID,PatientID,Gender,Age,HomeCity->Name AS "HomeCity", 11 | PatientGroup,TestScore From BI_Study.Patient 12 | UNION 13 | SELECT %ID,PatientID,Gender,Age,HomeCity, 14 | PatientGroup,TestScore From BI_Study.PatientSet2 15 | 16 | } 17 | 18 | /// This XData definition defines the output of this connector. 19 | XData Output [ XMLNamespace = "http://www.intersystems.com/deepsee/connector/output" ] 20 | { 21 | 22 | 24 | 25 | 27 | 28 | 30 | 31 | 33 | 34 | 36 | 37 | 39 | 40 | 42 | 43 | 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/BudgetCube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This is a sample DeepSee data model.
3 | /// This represents budget values for the HoleFoods model. 4 | /// Refer to the HoleFoods.BudgetCube class for more details. 5 | Class HoleFoods.BudgetCube Extends %DeepSee.CubeDefinition [ DependsOn = (HoleFoods.Cube, HoleFoods.Transaction, HoleFoods.KPIAction) ] 6 | { 7 | 8 | Parameter DOMAIN = "HOLEFOODS"; 9 | 10 | /// This xml document defines the HoleFoods model. 11 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 12 | { 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/cls/BI/Model/CityCube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class defines a cube based on BI.Study.City. 3 | /// Where applicable, the dimension, hierarchy, and level definitions here use the same names 4 | /// as in the Patients cube, so that these cubes can be used together. 5 | /// 6 | Class BI.Model.CityCube Extends %DeepSee.CubeDefinition [ DependsOn = BI.Study.City ] 7 | { 8 | 9 | Parameter DOMAIN = "PATIENTSAMPLE"; 10 | 11 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 12 | { 13 | 19 | 20 | 23 | 24 | 27 | 28 | 31 | 32 | 34 | 35 | 37 | 39 | 41 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/cls/BI/Model/SubjectAreas/DemoMDX.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a subject area based on the patients cube (BI.Model.PatientsCube). 4 | /// To view the subject area definition, open this class in Studio. 5 | /// 6 | Class BI.Model.SubjectAreas.DemoMDX Extends %DeepSee.SubjectArea [ DependsOn = BI.Model.PatientsCube ] 7 | { 8 | 9 | /// This XData definition defines the SubjectArea. 10 | XData SubjectArea [ XMLNamespace = "http://www.intersystems.com/deepsee/subjectarea" ] 11 | { 12 | 15 | 20 | 21 | 23 | 24 | 31 | 32 | 34 | 35 | 40 | 41 | 43 | 44 | 46 | 47 | 53 | } 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /Installer.cls: -------------------------------------------------------------------------------- 1 | Class App.Installer 2 | { 3 | 4 | XData setup 5 | { 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | } 40 | 41 | ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ] 42 | { 43 | #; Let XGL document generate code for this method. 44 | Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "setup") 45 | } 46 | 47 | ClassMethod SetDispatchClass(pApp As %String, pClass As %String) As %Status 48 | { 49 | New $Namespace 50 | Set $Namespace = "%SYS" 51 | Set tSC = ##class(Security.Applications).Get(pApp, .webProperties) 52 | If $$$ISERR(tSC) { 53 | Quit tSC 54 | } 55 | 56 | Set webProperties("DispatchClass") = pClass 57 | Set tSC = ##class(Security.Applications).Modify(pApp, .webProperties) 58 | Quit tSC 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/cls/BI/Model/RelCubes/RAllergies.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a cube based on BI.Study.PatientAllergy1. To view the cube definition, open 4 | /// this class in Studio or the BI Architect. 5 | /// The RelatedCubes/* cubes (like this one) use cube-to-cube relationships. 6 | Class BI.Model.RelCubes.RAllergies Extends %DeepSee.CubeDefinition [ DependsOn = (BI.Study.PatientAllergy1, BI.Model.RelCubes.RPatients), ProcedureBlock ] 7 | { 8 | 9 | Parameter DOMAIN = "PATIENTSAMPLE"; 10 | 11 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 12 | { 13 | 17 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | } 40 | 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/cls/BI/Model/RelCubes/RCities.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a cube based on BI.Study.City. To view the cube definition, open 4 | /// this class in Studio or the BI Architect. 5 | /// The RelatedCubes/* cubes (like this one) use cube-to-cube relationships. 6 | Class BI.Model.RelCubes.RCities Extends %DeepSee.CubeDefinition [ DependsOn = BI.Study.City ] 7 | { 8 | 9 | Parameter DOMAIN = "PATIENTSAMPLE"; 10 | 11 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 12 | { 13 | 18 | 19 | 24 | 25 | 26 | 30 | 31 | 33 | 35 | 37 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 52 | 53 | 55 | 56 | 57 | 58 | } 59 | 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/cls/BI/Model/RelCubes/RCityRainfall.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a cube based on BI.Study.CityRainfall To view the cube definition, open 4 | /// this class in Studio or the BI Architect. 5 | /// The RelatedCubes/* cubes (like this one) use cube-to-cube relationships. 6 | Class BI.Model.RelCubes.RCityRainfall Extends %DeepSee.CubeDefinition [ DependsOn = (BI.Study.CityRainfall, BI.Model.RelCubes.RCities) ] 7 | { 8 | 9 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 10 | { 11 | 17 | 18 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 41 | 42 | 46 | 47 | 49 | 50 | 51 | 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientAllergy1.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// An allergy has multiple pieces of information, 5 | /// which you can use separately or in combination to create dimensions, depending 6 | /// on what you want to see. 7 | Class BI.Study.PatientAllergy1 Extends %Persistent 8 | { 9 | 10 | /// Patient who has this allergy 11 | Property Patient As BI.Study.Patient; 12 | 13 | /// A substance to which the patient is allergic. 14 | Property Allergen As BI.Study.Allergen; 15 | 16 | /// Severity of this allergic reaction. 17 | Property Severity As BI.Study.AllergySeverity; 18 | 19 | /// Doctor who recorded this allergic reaction. 20 | Property DiagnosedBy As BI.Study.Doctor; 21 | 22 | ClassMethod CreateOne(patient As BI.Study.Patient, allergen As BI.Study.Allergen = "", severity As BI.Study.AllergySeverity = "", diagnosedBy As BI.Study.Doctor = "") As %Status 23 | { 24 | set new=..%New() 25 | set new.Patient=patient 26 | if (allergen'="") { 27 | set new.Allergen=allergen 28 | } 29 | if (severity'="") { 30 | set new.Severity=severity 31 | } 32 | if (diagnosedBy'="") { 33 | set new.DiagnosedBy=diagnosedBy 34 | } 35 | set status=new.%Save() 36 | quit status 37 | } 38 | 39 | Storage Default 40 | { 41 | 42 | 43 | %%CLASSNAME 44 | 45 | 46 | Patient 47 | 48 | 49 | Allergen 50 | 51 | 52 | Severity 53 | 54 | 55 | DiagnosedBy 56 | 57 | 58 | ^BI.Study.PatientAllergy1D 59 | PatientAllergy1DefaultData 60 | ^BI.Study.PatientAllergy1D 61 | ^BI.Study.PatientAllergy1I 62 | ^BI.Study.PatientAllergy1S 63 | %Storage.Persistent 64 | } 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/DemoCrossjoin.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This KPI demonstrates how to use an MDX crossjoin query in a KPI. 3 | /// 4 | Class BI.Model.KPIs.DemoCrossjoin Extends %DeepSee.KPI 5 | { 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 10 | { 11 | 12 | 13 | 14 | 15 | 16 | 17 | } 18 | 19 | Method %OnExecute() As %Status 20 | { 21 | set tSC = $$$OK 22 | try 23 | { 24 | set MDX = "SELECT {[Measures].[%COUNT],[Measures].[Avg Test Score]," 25 | _"[Measures].[Avg Allergy Count]} ON 0," 26 | _"NONEMPTYCROSSJOIN([AgeD].[Age Group].Members,[PatGrpD].[Patient Group].Members) ON 1 " 27 | _"FROM [Patients]" 28 | 29 | // Create a result set from the query 30 | set dsRS=##class(%DeepSee.ResultSet).%New() 31 | set status = dsRS.%PrepareMDX(MDX) 32 | set status = dsRS.%Execute() 33 | 34 | // Get the number of rows and columns 35 | set rowCount = dsRS.%GetRowCount() 36 | set colCount = dsRS.%GetColumnCount() 37 | 38 | set ..%seriesCount=rowCount 39 | 40 | // Iterate through rows 41 | for rows = 1:1:..%seriesCount 42 | { 43 | // Row dimensions are stored as labels. The second parameter is 2 for rows (columns would be 1) 44 | do dsRS.%GetOrdinalLabel(.label,2,rows) 45 | 46 | // Fetch the two labels and concatenate them to create name of series 47 | set ..%seriesNames(rows)=label(2)_" / "_label(1) 48 | 49 | // Iterate through the columns 50 | for col = 1:1:colCount 51 | { 52 | // Get value in cell 53 | set tValue= dsRS.%GetOrdinalValue(col,rows) 54 | 55 | // The measures can be taken out of the cells in the ResultSet 56 | Set:col=1 ..%data(rows,"Patient Count") = tValue 57 | Set:col=2 ..%data(rows,"Avg Test Score") = tValue 58 | Set:col=3 ..%data(rows,"Avg Allergy Count") = tValue 59 | } 60 | } 61 | } 62 | catch(ex) { 63 | Set tSC = ex.AsStatus() 64 | } 65 | quit tSC 66 | } 67 | 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/DemoSQL.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This KPI class uses an SQL query and defines one filter. 3 | Class BI.Model.KPIs.DemoSQL Extends %DeepSee.KPI 4 | { 5 | 6 | Parameter DOMAIN = "PATIENTSAMPLE"; 7 | 8 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 9 | { 10 | 13 | 14 | 17 | 18 | 21 | 22 | 25 | 26 | 27 | } 28 | 29 | /// This callback defines the basic SQL query and also checks for the current values 30 | /// in the filter. The callback adds an SQL WHERE clause with one of the following forms, 31 | /// depending on the user's selections: 32 | /// WHERE HomeCity->PostalCode = zip_code_selected_by_user 33 | /// WHERE HomeCity->PostalCode IN (zip_code_1,zip_code_2,...) 34 | /// WHERE HomeCity->PostalCode <> zip_code_selected_by_user 35 | /// WHERE HomeCity->PostalCode NOT IN (zip_code_1,zip_code_2,...) 36 | Method %OnGetSQL(ByRef pSQL As %String) As %Status 37 | { 38 | // This is the start of the SQL query for this KPI 39 | set pSQL = "SELECT HomeCity->Name, Count(*),AVG(Age) FROM BI_Study.Patient " 40 | 41 | set where = "" 42 | 43 | // Look at %filterValues to see if a filter has been applied to this KPI instance 44 | if $IsObject(..%filterValues) { 45 | if (..%filterValues.ZipCode'="") 46 | { 47 | // Call utility method that returns filter data in convenient format 48 | set sqlstring=..%GetSQLForFilter("HomeCity->PostalCode","ZipCode") 49 | set where = "WHERE "_sqlstring 50 | 51 | // Old version -- this works but only if you disable multiselect for this fitler 52 | // set where = "WHERE HomeCity->PostalCode = '" _ ..%filterValues.ZipCode _ "' " 53 | } 54 | } 55 | 56 | set groupby="GROUP BY HomeCity " 57 | set orderby="ORDER BY HomeCity " 58 | // assemble the SQL statement 59 | set pSQL=pSQL_where_groupby_orderby 60 | quit $$$OK 61 | } 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/DemoInteroperability.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | Class BI.Model.KPIs.DemoInteroperability Extends BI.Utils.MDXAutoFiltersKPI 3 | { 4 | 5 | Parameter CUBE = "PATIENTS"; 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 10 | { 11 | 13 | 14 | 15 | 16 | 17 | 18 | } 19 | 20 | Method %OnGetMDX(ByRef pMDX As %String) As %Status 21 | { 22 | set yaxis=", NON EMPTY [profd].[h1].[profession].MEMBERS ON 1" 23 | // Check custom filter value 24 | if (..%filterValues."Yaxis"'="") { 25 | set yaxis=", NON EMPTY "_..%filterValues.Yaxis_".MEMBERS ON 1" 26 | } 27 | set pMDX="SELECT {MEASURES.[%COUNT],MEASURES.[avg age]} on 0"_yaxis_" FROM "_..#CUBE 28 | 29 | /// Append a %FILTER clause to handle any other filter values 30 | Set pMDX = pMDX _ ..FilterBuilder() 31 | Quit $$$OK 32 | } 33 | 34 | /// Implementation. 35 | ClassMethod %OnGetFilterList(ByRef pFilters As %List, pDataSourceName As %String = "") As %Status 36 | { 37 | // Call method in superclass so we can get filters of the associated cube 38 | set tSC=##super(.pFilters,pDataSourceName) 39 | quit:$$$ISERR(tSC) tSC 40 | 41 | // Update pFilters array to include the custom filter 42 | set pFilters($i(pFilters)) = $lb("Yaxis","Yaxis",,0) 43 | 44 | quit $$$OK 45 | } 46 | 47 | /// Implementation. 48 | ClassMethod %OnGetFilterMembers(pFilter As %String, Output pMembers As %List, pSearchKey As %String = "", pDataSourceName As %String = "") As %Status 49 | { 50 | set pMembers="" 51 | if (pFilter="Yaxis") { 52 | set pMembers($I(pMembers))=$LB("Home City","[homed].[h1].[city]") 53 | set pMembers($I(pMembers))=$LB("Favorite Color","[colord].[h1].[favorite color]") 54 | set pMembers($I(pMembers))=$LB("Profession","[profd].[h1].[profession]") 55 | set pMembers($I(pMembers))=$LB("Diagnoses","[diagd].[h1].[diagnoses]") 56 | } else { 57 | //call method in superclass so we can get filter members for the associated cube 58 | do ..%GetMembersForFilter(..#CUBE,pFilter,.pMembers,pSearchKey) 59 | } 60 | quit $$$OK 61 | } 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /dev.md: -------------------------------------------------------------------------------- 1 | # Developer Notes 2 | 3 | This file complements the [main README](README.md) with additional background on how this sample can be set up and what automation was added. 4 | 5 | ## Files used in this repository 6 | 7 | Sample code 8 | * `src/cls/`: This folder contains the main ObjectScript code for this sample and its contents is described in the [main README](README.md) 9 | * `src/gbl/ZipCodeData.xml` contains a global export with static data used in the sample 10 | 11 | Setup options 12 | * Manual setup: 13 | * `buildsample/Build.SampleBI.xml` has the ObjectScript code to manually configure and populate the sample, as explained in the [main README](README.md) 14 | * ZPM setup: 15 | * `module.xml` is the main descriptor file for setting up the sample through [ZPM](https://github.com/intersystems-community/zpm), as an alternative to the manual setup procedure 16 | * Docker setup: 17 | * `Dockerfile` has the build recipe for building an entire Docker image out of this sample repository 18 | * `iris.script` has ObjectScript code to set up the sample namespace and then invokes ZPM for setting up the actual sample as described above. 19 | * `Installer.cls` is an [installation manifest](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCI_MANIFEST) called by `iris.script` to set up the sample namespace 20 | * `.dockerignore` is a standard Docker configuration file to leave some repository contents out of the Docker build scope 21 | * `docker-compose.xml` adds convenience by scripting how to launch a container based on that image. 22 | 23 | Miscellaneous 24 | * `.vscode` is a configuration file for [Visual Studio Code](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_vscode), the recommended editor for ObjectScript code on InterSystems IRIS 25 | * `.gitattributes` and `.gitignore` are configuration files for Git source control and otherwise don't impact the sample 26 | * `.github/workflows/` has a few scripts for automated CI/CD workflows, leveraging [GitHub Actions](https://github.com/features/actions) 27 | 28 | ## Useful commands 29 | 30 | ### Build container with no cache 31 | ``` 32 | docker-compose build --no-cache --progress=plain 33 | ``` 34 | 35 | ### Open terminal to docker in a NAMESPACE 36 | ``` 37 | docker-compose exec iris iris session iris -U IRISAPP 38 | ``` 39 | 40 | ### Clear docker fs 41 | ``` 42 | docker system prune -f 43 | ``` 44 | 45 | ### Open SQL shell 46 | ```ObjectScript 47 | d $System.SQL.Shell() 48 | ``` 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/DemoMDX.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This KPI class uses an MDX query and has three filters. 3 | /// For each filter, multiSelect is false, which simplifies the query construction. 4 | Class BI.Model.KPIs.DemoMDX Extends %DeepSee.KPI 5 | { 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 10 | { 11 | 16 | 17 | 20 | 21 | 24 | 25 | 28 | 29 | 32 | 33 | 36 | 37 | 38 | } 39 | 40 | /// In this implementation: Given a filter (in this case an MDX level identifier), 41 | /// this method returns the list of members in the internal form needed by the KPI. 42 | ClassMethod %OnGetFilterMembers(pFilter As %String, Output pMembers As %List) As %Status 43 | { 44 | set status = $$$OK 45 | 46 | try { 47 | do ..%GetMembersForFilter("Patients.cube",pFilter,.pMembers) 48 | } 49 | catch(ex) { 50 | set status = ex.AsStatus() 51 | } 52 | 53 | quit status 54 | } 55 | 56 | /// In this implementation: This method adds a %FILTER clause for each non-null 57 | /// filter value. Because multiselect is off, query construction is fairly simple. 58 | Method %OnGetMDX(ByRef pMDX As %String) As %Status 59 | { 60 | if (..%filterValues."[homed].[h1].[zip]"'="") 61 | { 62 | set pMDX = pMDX _ " %FILTER [homed].[h1].[zip]." _..%filterValues."[homed].[h1].[zip]" 63 | } 64 | 65 | if (..%filterValues."[gend].[h1].[gender]"'="") 66 | { 67 | set pMDX = pMDX _ " %FILTER [gend].[h1].[gender]." _..%filterValues."[gend].[h1].[gender]" 68 | } 69 | 70 | if (..%filterValues."[aged].[h1].[age group]"'="") 71 | { 72 | set pMDX = pMDX _ " %FILTER [aged].[h1].[age group]." _..%filterValues."[aged].[h1].[age group]" 73 | } 74 | 75 | quit $$$OK 76 | } 77 | 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/DemoTrendLines.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This KPI class uses an MDX query that uses %LIST to return a list of values 3 | /// for use as a trend line in a scorecard. 4 | /// For each filter, multiSelect is false, which simplifies the query construction. 5 | /// (The KPI query would be incorrectly formed if the user selected multiple values 6 | /// or used the EXCLUDE option.) 7 | /// The KPI will not work if a URL parameter specifies multiple values or %NOT. 8 | Class BI.Model.KPIs.DemoTrendLines Extends %DeepSee.KPI 9 | { 10 | 11 | Parameter DOMAIN = "PATIENTSAMPLE"; 12 | 13 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 14 | { 15 | 20 | 21 | 24 | 25 | 28 | 29 | 32 | 33 | 36 | 37 | 38 | } 39 | 40 | /// In this implementation: Given a filter (in this case an MDX level identifier), 41 | /// this method returns the list of members in the internal form needed by the KPI. 42 | ClassMethod %OnGetFilterMembers(pFilter As %String, Output pMembers As %List) As %Status 43 | { 44 | set status = $$$OK 45 | 46 | try { 47 | do ..%GetMembersForFilter("Patients.cube",pFilter,.pMembers) 48 | } 49 | catch(ex) { 50 | set status = ex.AsStatus() 51 | } 52 | 53 | quit status 54 | } 55 | 56 | /// In this implementation: Given a filter (in this case an MDX level identifier), 57 | /// this method returns the list of members in the internal form needed by the KPI. 58 | Method %OnGetMDX(ByRef pMDX As %String) As %Status 59 | { 60 | 61 | if (..%filterValues."[gend].[h1].[gender]"'="") 62 | { 63 | set pMDX = pMDX _ " %FILTER [gend].[h1].[gender]." _..%filterValues."[gend].[h1].[gender]" 64 | } 65 | 66 | if (..%filterValues."[homed].[h1].[zip]"'="") 67 | { 68 | set pMDX = pMDX _ " %FILTER [homed].[h1].[zip]." _..%filterValues."[homed].[h1].[zip]" 69 | } 70 | 71 | quit $$$OK 72 | } 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/PluginDemo.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This simple plug-in demo provides two properties: 3 | /// PatientCount, which behaves the same as the %COUNT measure 4 | /// HighScoreCount, which counts the patients with TestScore greater than 95. 5 | Class BI.Model.KPIs.PluginDemo Extends %DeepSee.KPIPlugIn 6 | { 7 | 8 | /// Display this one in the Analyzer 9 | Parameter PUBLIC = 1; 10 | 11 | /// This plug-in works only with one cube 12 | Parameter BASECUBE = "Patients"; 13 | 14 | /// Query the fact table rather than the source table 15 | Parameter LISTINGSOURCE = "FactTable"; 16 | 17 | /// Display this plug-in in the Analyzer for drag & drop use 18 | Parameter PLUGINTYPE = "Pivot"; 19 | 20 | /// Specifies the field list (RETURN clause) of the listing used to supply data for this 21 | /// plug-in. 22 | Parameter LISTINGFIELDS As STRING = "MxTestScore"; 23 | 24 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 25 | { 26 | 27 | 28 | 29 | 31 | 32 | 33 | } 34 | 35 | /// Get the base query for this plug-in. 36 | Method %OnGetMDX(ByRef pMDX As %String) As %Status 37 | { 38 | set pMDX = "SELECT FROM "_..#BASECUBE 39 | quit $$$OK 40 | } 41 | 42 | /// As input, this method receives a statement result that is the result of a listing query 43 | Method %OnCompute(pSQLRS As %SQL.StatementResult, pFactCount As %Integer) As %Status 44 | { 45 | set tSC = $$$OK 46 | Try { 47 | // Place answer in KPI output 48 | set ..%seriesCount = 1 49 | set ..%seriesNames(1) = "PluginDemo" 50 | 51 | // Set Count property of KPI -- just use received pFactCount 52 | set ..%data(1,"PatientCount") = pFactCount 53 | 54 | // Iterate through result set to get HighScoreCount 55 | set n = 0 56 | set highcount = 0 57 | while (pSQLRS.%Next(.tSC)) { 58 | if $$$ISERR(tSC) Quit 59 | set n = n + 1 60 | 61 | set testscore = pSQLRS.MxTestScore 62 | if (testscore>95) { 63 | set highcount = highcount + 1 64 | } 65 | 66 | // Update pct complete 67 | if (n#100 = 0) { 68 | Do ..%SetPercentComplete(100*(n/pFactCount)) 69 | } 70 | } 71 | set ..%data(1,"HighScoreCount") = highcount 72 | 73 | } 74 | catch(ex) { 75 | set tSC = ex.AsStatus() 76 | } 77 | quit tSC 78 | } 79 | 80 | } 81 | 82 | -------------------------------------------------------------------------------- /src/cls/BI/Model/CompoundCube/CityRainfall.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use in a compound cube (and can also be used on its own). 3 | /// To view the cube definition, open this class in Studio. 4 | Class BI.Model.CompoundCube.CityRainfall Extends %DeepSee.CubeDefinition [ DependsOn = (BI.Study.CityRainfall, BI.Model.CompoundCube.Patients) ] 5 | { 6 | 7 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 8 | { 9 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 39 | 41 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 60 | 61 | 63 | 64 | 65 | 67 | 68 | 69 | 70 | } 71 | 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/cls/BI/Model/RelCubes/RDoctors.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a cube based on BI.Study.Doctors. 4 | /// To view the cube definition, open this class in Studio or the BI Architect. 5 | /// The RelatedCubes/* cubes (like this one) use cube-to-cube relationships. 6 | Class BI.Model.RelCubes.RDoctors Extends %DeepSee.CubeDefinition [ DependsOn = (BI.Study.Doctor, BI.Model.RelCubes.RCities) ] 7 | { 8 | 9 | Parameter DOMAIN = "PATIENTSAMPLE"; 10 | 11 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 12 | { 13 | 19 | 20 | 26 | 27 | 34 | 35 | 37 | 38 | 41 | 44 | 49 | 50 | 51 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | 62 | 66 | 67 | 71 | 72 | 74 | 75 | 76 | 77 | } 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/cls/BI/Model/PatientsQueryCube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class contains a cube based on BI.Model.PatientsQuery. 3 | /// This cube is not built by default. 4 | Class BI.Model.PatientsQueryCube Extends %DeepSee.CubeDefinition [ DependsOn = BI.Model.PatientsQuery ] 5 | { 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 10 | { 11 | 17 | 18 | 21 | 22 | 25 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 63 | 64 | 68 | 69 | 72 | 73 | 76 | 77 | 80 | 81 | 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/cls/BI/Model/RainfallCube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class contains a cube based on BI.Study.CityRainfall. 3 | /// The dimension, hierarchy, and level definitions here use the same names 4 | /// as in the Patients cube, so that these cubes can be used together. 5 | Class BI.Model.RainfallCube Extends %DeepSee.CubeDefinition [ DependsOn = BI.Study.CityRainfall ] 6 | { 7 | 8 | Parameter DOMAIN = "PATIENTSAMPLE"; 9 | 10 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 11 | { 12 | 18 | 19 | 21 | 22 | 24 | 26 | 28 | 30 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 60 | 61 | 64 | 65 | 67 | 68 | 69 | 70 | } 71 | 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/cls/BI/Study/AllergySeverity.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class contains the allergy severity lookup table. 5 | /// You can extend or modify the data contained here by editing the XData block in this class. 6 | Class BI.Study.AllergySeverity Extends %Persistent 7 | { 8 | 9 | /// Unique code for the allergy severity 10 | Property Code As %String; 11 | 12 | /// Unique description (user-visible name) for the allergy severity 13 | Property Description As %String; 14 | 15 | XData LoadData 16 | { 17 | 18 | 001^Minor 19 | 002^Moderate 20 | 003^Life-threatening 21 | 009^Inactive 22 | 099^Unable to determine 23 |
24 | } 25 | 26 | /// This method reads the XData block in this class and uses it to populate the table. 27 | /// This method is called by BI.Populate:GenerateData(). 28 | ClassMethod Setup() As %Status 29 | { 30 | set status=$$$OK 31 | // First kill extent 32 | // Never use %KillExtent() in a real application 33 | Do ..%KillExtent() 34 | 35 | // Get a stream of XML from the XData block contained in this class 36 | set tStream=##class(%Dictionary.CompiledXData).IDKEYOpen($CLASSNAME(),"LoadData").Data 37 | if '$IsObject(tStream) {set tSC=%objlasterror Quit} 38 | 39 | set status=##class(%XML.TextReader).ParseStream(tStream,.textreader) 40 | 41 | // Check status 42 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit} 43 | 44 | // Iterate through document, node by node 45 | while textreader.Read() 46 | { 47 | if (textreader.NodeType="chars") 48 | { 49 | set value=textreader.Value 50 | //write !, "value is: ", value 51 | set obj=..%New() 52 | set obj.Code=$Piece(value,"^",1) 53 | set obj.Description=$Piece(value,"^",2) 54 | set status=obj.%Save() 55 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit} 56 | } 57 | } 58 | 59 | set status=##class(BI.Populate).UpdateIdCache($CLASSNAME()) 60 | 61 | quit status 62 | } 63 | 64 | Storage Default 65 | { 66 | 67 | 68 | %%CLASSNAME 69 | 70 | 71 | Code 72 | 73 | 74 | Description 75 | 76 | 77 | ^BI.Study.AllergySeverityD 78 | AllergySeverityDefaultData 79 | ^BI.Study.AllergySeverityD 80 | ^BI.Study.AllergySeverityI 81 | ^BI.Study.AllergySeverityS 82 | %Storage.Persistent 83 | } 84 | 85 | } 86 | 87 | -------------------------------------------------------------------------------- /src/cls/BI/Model/ConnectorCube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class contains a cube based on BI.Model.ConnectorExample. 3 | Class BI.Model.ConnectorCube Extends %DeepSee.CubeDefinition [ DependsOn = BI.Model.ConnectorExample ] 4 | { 5 | 6 | Parameter DOMAIN = "PATIENTSAMPLE"; 7 | 8 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 9 | { 10 | 16 | 17 | 20 | 21 | 24 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 57 | 58 | 59 | 62 | 63 | 67 | 68 | 71 | 72 | 75 | 76 | 79 | 80 | 83 | 84 | 85 | 86 | } 87 | 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/DemoDataChanges.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This KPI class is intended for use in a dashboard that demos real-time updates using 3 | /// the Patients sample. The actions in this class invoke methods in that sample 4 | /// that add, change, or delete data. 5 | /// The actions are defined in the %OnDashboardAction() callback. The XData block in 6 | /// this class contains one element for each action, to advertise these actions 7 | /// to the widget builder in the user interface. 8 | /// This KPI class also defines a simple one-cell KPI which is displayed in a text meter 9 | /// widget on that dashboard. (An alternative way to access these actions from ANY dashboard 10 | /// would be to use this class as the actionClass for the Patients cube.) 11 | /// To see the full KPI definition, open this class in Studio. 12 | Class BI.Model.KPIs.DemoDataChanges Extends %DeepSee.KPI 13 | { 14 | 15 | Parameter DOMAIN = "PATIENTSAMPLE"; 16 | 17 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 18 | { 19 | 23 | 24 | 27 | 28 | 30 | 31 | 33 | 34 | 36 | 37 | 39 | 40 | 42 | 43 | 45 | 46 | 47 | } 48 | 49 | ClassMethod %OnDashboardAction(pAction As %String, pContext As %ZEN.proxyObject) As %Status 50 | { 51 | set sc = $$$OK 52 | try{ 53 | if (pAction = "AddPatients") { 54 | job ##class(BI.Study.Patient).AddPatients() 55 | } 56 | elseif (pAction="ChangeFavoriteColors") 57 | { 58 | job ##class(BI.Study.PatientDetails).ChangePatientDetails() 59 | } 60 | elseif (pAction="ChangePatientGroups") 61 | { 62 | job ##class(BI.Study.Patient).ChangePatientGroups() 63 | } 64 | elseif (pAction="AddEncounters") 65 | { 66 | job ##class(BI.Study.PatientEncounter).AddEncounters() 67 | } 68 | elseif (pAction="DeleteSomePatients") 69 | { 70 | job ##class(BI.Study.Patient).DeleteSomePatients() 71 | } 72 | elseif (pAction="ChangeSomeDoctors") 73 | { 74 | job ##class(BI.Study.Doctor).ChangeSomeDoctors() 75 | } 76 | } 77 | Catch(ex) { 78 | set sc = ex.AsStatus() 79 | } 80 | quit sc 81 | } 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /src/cls/BI/Model/ConnectorExample.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class defines an example of a data connector. 3 | /// The query for this connector uses a local table. 4 | Class BI.Model.ConnectorExample Extends %DeepSee.DataConnector 5 | { 6 | 7 | /// This connector supports "idlist" mode 8 | Parameter SUPPORTSIDLIST = 1; 9 | 10 | /// This connector supports "single" mode 11 | Parameter SUPPORTSSINGLE = 1; 12 | 13 | /// This XData definition defines the output of this connector. 14 | XData Output [ XMLNamespace = "http://www.intersystems.com/deepsee/connector/output" ] 15 | { 16 | 17 | 20 | 21 | 23 | 24 | 26 | 27 | 29 | 30 | 32 | 33 | 36 | 37 | 39 | 40 | 41 | } 42 | 43 | /// Implementation 44 | Method %OnGetSourceResultSet(ByRef pParameters, Output pResultSet) As %Status 45 | { 46 | set tSC = $$$OK 47 | set pResultSet = "" 48 | try { 49 | // Write the basic SQL query 50 | set sql="SELECT %ID,PatientID,Gender,Age,HomeCity->Name AS ""HomeCity""" 51 | _",PatientGroup,TestScore From BI_Study.Patient " 52 | 53 | if (..%mode="single") { 54 | set sql=sql_"WHERE %ID = ?" 55 | } elseif (..%mode="idlist") { 56 | set sql = sql _ "WHERE %ID in (select _DSsourceId from " 57 | _ ..%listingTable _ " where _DSqueryKey = ?)" 58 | } 59 | 60 | set tStatement = ##class(%SQL.Statement).%New() 61 | set tSC = tStatement.%Prepare(.sql) 62 | 63 | if $$$ISERR(tSC) { 64 | set ex = ##class(%Exception.StatusException).CreateFromStatus(tSC) 65 | throw ex 66 | } 67 | 68 | if (..%mode="single") { 69 | // Pass the ID as a parameter 70 | set pResultSet = tStatement.%Execute(..%singleId) 71 | } elseif (..%mode="idlist") { 72 | // Pass in the listing key as a parameter 73 | set pResultSet = tStatement.%Execute(..%listingKey) 74 | } else { 75 | set pResultSet = tStatement.%Execute() 76 | } 77 | 78 | // Check %SQLCODE and report if there's an error 79 | if pResultSet.%SQLCODE { 80 | set sqlcode=pResultSet.%SQLCODE 81 | set message=pResultSet.%Message 82 | set ex = ##class(%Exception.SQL).CreateFromSQLCODE(sqlcode, message) 83 | throw ex 84 | } 85 | 86 | } 87 | catch(ex) { 88 | Set tSC = ex.AsStatus() 89 | } 90 | 91 | quit tSC 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/cls/BI/Model/CompoundCube/Doctors.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use in a compound cube (and can also be used on its own). 3 | /// To view the cube definition, open this class in Studio. 4 | Class BI.Model.CompoundCube.Doctors Extends %DeepSee.CubeDefinition [ DependsOn = (BI.Study.Doctor, BI.Model.CompoundCube.Patients) ] 5 | { 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 10 | { 11 | 21 | 22 | 25 | 26 | 29 | 32 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 47 | 48 | 49 | 50 | 55 | 56 | 58 | 60 | 62 | 64 | 65 | 66 | 67 | 68 | 72 | 73 | 77 | 78 | 80 | 81 | 82 | 84 | 85 | 86 | 87 | } 88 | 89 | } 90 | 91 | -------------------------------------------------------------------------------- /src/cls/BI/Model/KPIs/BubbleChartDemo.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Sample KPI for HoleFoods Demo. 3 | /// This KPI provides synthetic corporate data and defines some simple actions. 4 | Class BI.Model.KPIs.BubbleChartDemo Extends %DeepSee.KPI 5 | { 6 | 7 | /// This XData definition defines the KPI. 8 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 9 | { 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | } 19 | 20 | /// Notify subclass that KPI is has just be executed. 21 | /// This is a good place to override properties, such as range and threshold. 22 | Method %OnLoadKPI() As %Status 23 | { 24 | set n=1 25 | set ..%seriesNames(n)="Alpha" 26 | set ..%data(n,"x")=15 27 | set ..%data(n,"y")=327 28 | set ..%data(n,"radius")=$R(6)+4 29 | set ..%data(n,"color")=$R(3) 30 | set ..%data(n,"opacity")=$R(7)+4 31 | 32 | set n=2 33 | set ..%seriesNames(n)="Beta" 34 | set ..%data(n,"x")=10 35 | set ..%data(n,"y")=200 36 | set ..%data(n,"radius")=$R(6)+4 37 | set ..%data(n,"color")=$R(3) 38 | set ..%data(n,"opacity")=$R(7)+4 39 | 40 | set n=3 41 | set ..%seriesNames(n)="Gamma" 42 | set ..%data(n,"x")=22 43 | set ..%data(n,"y")=256 44 | set ..%data(n,"radius")=$R(6)+4 45 | set ..%data(n,"color")=$R(3) 46 | set ..%data(n,"opacity")=$R(7)+4 47 | 48 | set n=4 49 | set ..%seriesNames(n)="Delta" 50 | set ..%data(n,"x")=17 51 | set ..%data(n,"y")=193 52 | set ..%data(n,"radius")=$R(6)+4 53 | set ..%data(n,"color")=$R(3) 54 | set ..%data(n,"opacity")=$R(7)+4 55 | 56 | set n=5 57 | set ..%seriesNames(n)="Epsilon" 58 | set ..%data(n,"x")=27 59 | set ..%data(n,"y")=281 60 | set ..%data(n,"radius")=$R(6)+4 61 | set ..%data(n,"color")=$R(3) 62 | set ..%data(n,"opacity")=$R(7)+4 63 | 64 | set n=6 65 | set ..%seriesNames(n)="Zeta" 66 | set ..%data(n,"x")=33 67 | set ..%data(n,"y")=301 68 | set ..%data(n,"radius")=$R(6)+4 69 | set ..%data(n,"color")=$R(3) 70 | set ..%data(n,"opacity")=$R(7)+4 71 | 72 | set n=7 73 | set ..%seriesNames(n)="Eta" 74 | set ..%data(n,"x")=25 75 | set ..%data(n,"y")=310 76 | set ..%data(n,"radius")=$R(6)+4 77 | set ..%data(n,"color")=$R(3) 78 | set ..%data(n,"opacity")=$R(7)+4 79 | 80 | set n=8 81 | set ..%seriesNames(n)="Theta" 82 | set ..%data(n,"x")=17 83 | set ..%data(n,"y")=399 84 | set ..%data(n,"radius")=$R(6)+4 85 | set ..%data(n,"color")=$R(3) 86 | set ..%data(n,"opacity")=$R(7)+4 87 | 88 | set n=9 89 | set ..%seriesNames(n)="Iota" 90 | set ..%data(n,"x")=35 91 | set ..%data(n,"y")=175 92 | set ..%data(n,"radius")=$R(6)+4 93 | set ..%data(n,"color")=$R(3) 94 | set ..%data(n,"opacity")=$R(7)+4 95 | 96 | set n=10 97 | set ..%seriesNames(n)="Kappa" 98 | set ..%data(n,"x")=28 99 | set ..%data(n,"y")=255 100 | set ..%data(n,"radius")=$R(6)+4 101 | set ..%data(n,"color")=$R(3) 102 | set ..%data(n,"opacity")=$R(7)+4 103 | 104 | set ..%seriesCount=n 105 | quit $$$OK 106 | } 107 | 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/cls/BI/Study/Allergen.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class contains the allergen code lookup table. 5 | /// You can extend or modify the data contained here by editing the XData block in this class. 6 | Class BI.Study.Allergen Extends %Persistent 7 | { 8 | 9 | /// Unique code for the allergen 10 | Property Code As %String; 11 | 12 | /// Unique description (user-visible name) for the allergen 13 | Property Description As %String; 14 | 15 | /// Format: code^description 16 | /// The first row is special: this is the "allergen" that represents no known allergies. 17 | /// We treat this one differently when creating patient allergens. 18 | XData LoadData 19 | { 20 | 21 | 000^nil known allergies 22 | 001^additive/coloring agent 23 | 002^animal dander 24 | 003^ant bites 25 | 004^bee stings 26 | 005^dairy products 27 | 006^dust mites 28 | 007^eggs 29 | 008^fish 30 | 009^mold 31 | 010^peanuts 32 | 011^pollen 33 | 012^shellfish 34 | 013^soy 35 | 014^tree nuts 36 | 015^wheat 37 |
38 | } 39 | 40 | /// This method reads the XData block in this class and uses it to populate the table. 41 | /// This method is called by BI.Populate:GenerateData(). 42 | ClassMethod Setup() As %Status 43 | { 44 | set status=$$$OK 45 | // First kill extent 46 | // Never use %KillExtent() in a real application 47 | do ..%KillExtent() 48 | 49 | // Get a stream of XML from the XData block contained in this class 50 | set tStream=##class(%Dictionary.CompiledXData).IDKEYOpen($CLASSNAME(),"LoadData").Data 51 | if '$IsObject(tStream) {set tSC=%objlasterror quit} 52 | 53 | set status=##class(%XML.TextReader).ParseStream(tStream,.textreader) 54 | 55 | // Check status 56 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 57 | 58 | // Iterate through document, node by node 59 | while textreader.Read() 60 | { 61 | if (textreader.NodeType="chars") 62 | { 63 | set value=textreader.Value 64 | //write !, "value is: ", value 65 | set obj=..%New() 66 | set obj.Code=$Piece(value,"^",1) 67 | set obj.Description=$Piece(value,"^",2) 68 | set status=obj.%Save() 69 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 70 | } 71 | } 72 | quit status 73 | } 74 | 75 | Storage Default 76 | { 77 | 78 | 79 | %%CLASSNAME 80 | 81 | 82 | Code 83 | 84 | 85 | Description 86 | 87 | 88 | ^BI.Study.AllergenD 89 | AllergenDefaultData 90 | ^BI.Study.AllergenD 91 | ^BI.Study.AllergenI 92 | ^BI.Study.AllergenS 93 | %Storage.Persistent 94 | } 95 | 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/cls/BI/Model/PortletDemo/ClockPortlet.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | Class BI.Model.PortletDemo.ClockPortlet Extends %DeepSee.Component.Portlet.abstractPortlet 3 | { 4 | 5 | Property srcparams As %String; 6 | 7 | /// Static HTML display method: draw the BODY of this component as HTML. 8 | Method %DrawHTML() 9 | { 10 | set size=$G(..settings("SIZE")) 11 | set ..srcparams="" 12 | for val="LOGO","STEP","OFFSET","CIRCLE","UTC","SIZE" set ..srcparams=..srcparams_val_"="_$G(..settings(val))_"&" 13 | 14 | &html<
15 | 17 |
> 18 | } 19 | 20 | /// Return the URL of the icon to display for this portlet. 21 | /// This is displayed in the Widget Builder dialog. 22 | /// This should be overridden in subclasses. 23 | ClassMethod %OnGetPortletIcon() As %String 24 | { 25 | quit "../broker/deepsee/insert_table_clock_48.png" 26 | } 27 | 28 | /// Return the localized caption of this portlet. 29 | /// This is displayed in the Widget Builder dialog. 30 | /// This should be overridden in subclasses. 31 | ClassMethod %OnGetPortletName() As %String 32 | { 33 | quit "AnalogClock" 34 | } 35 | 36 | /// Return an optional array of "settings" values for this portlet. 37 | /// The list of settings is displayed in the Widget Builder where the user can view and 38 | /// edit them. 39 | /// When the portlet is rendered, the values of all settings is made available to the 40 | /// portlet's %DrawHTML method via the settings--a 41 | /// multidimensional array subscripted by setting name. 42 | /// On return, pInfo can contain a list of settings in the form: 43 | /// pInfo(n) = $LB(name,value,type,caption,title) 44 | /// name is the logical name of the setting. 45 | /// value is the default value of the setting. 46 | /// type indicates the type of the setting. This determines the control 47 | /// displayed to get the value of the setting. If omitted the type is assumed to be a string. 48 | /// The type can be: "%Integer", "%Boolean", or "ENUM^caption1:value1,caption2:value2". 49 | /// caption is the localized caption of the setting. 50 | /// title is an optional tooltip displayed for the setting. 51 | ClassMethod %OnGetPortletSettings(Output pInfo As %List, ByRef pSettings) As %Status 52 | { 53 | kill pInfo 54 | set pInfo($I(pInfo)) = $LB("LOGO",$G(pSettings("LOGO")),"","Clock logo","Logo displayed on top of clock") 55 | set pInfo($I(pInfo)) = $LB("STEP",$G(pSettings("STEP"),"10"),"%Integer","Second hand redraw interval (msec)","milliseconds steps of second hand") 56 | set pInfo($I(pInfo)) = $LB("OFFSET",$G(pSettings("OFFSET"),"0"),"%Integer","Offset from base time (min)","minutes difference from base time (Local or UTC)") 57 | set pInfo($I(pInfo)) = $LB("UTC",$G(pSettings("UTC"),"0"),"%Boolean","UTC","Time Base: local (default) or UTC") 58 | set pInfo($I(pInfo)) = $LB("CIRCLE",$G(pSettings("CIRCLE"),"1"),"%Boolean","Circle","Shape: square (default) or circle") 59 | set pInfo($I(pInfo)) = $LB("SIZE",$G(pSettings("SIZE"),"150"),"%Integer","Size","Size of the clock") 60 | 61 | quit pInfo 62 | } 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/KPISQL.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Example KPI definition using SQL statements against the HoleFoods transaction data. 3 | Class HoleFoods.KPISQL Extends %DeepSee.KPI [ DependsOn = HoleFoods.Transaction ] 4 | { 5 | 6 | /// This XData definition defines the KPI. 7 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 8 | { 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | } 25 | 26 | /// This callback, if implements, lets a subclass provide an SQL statement to fetch data for this KPI. 27 | Method %OnGetSQL(ByRef pSQL As %String) As %Status 28 | { 29 | if $IsObject(..%filterValues) { 30 | set tWHERE = "" 31 | if (..%filterValues.City'="") { 32 | set tWHERE = tWHERE _ $S(tWHERE="":"",1:" AND ") _ " Outlet->City = '" _ ..%filterValues.City _"'" 33 | } 34 | if (..%filterValues.Product'="") { 35 | set tWHERE = tWHERE _ $S(tWHERE="":"",1:" AND ") _ " Product = '" _ ..%filterValues.Product _"'" 36 | } 37 | 38 | if (tWHERE'="") { 39 | // insert WHERE clase within query 40 | set tSQL1 = $P(pSQL,"GROUP BY",1) 41 | set tSQL2 = $P(pSQL,"GROUP BY",2) 42 | set pSQL = tSQL1 _ " WHERE " _ tWHERE 43 | if (tSQL2 '= "") { 44 | set pSQL = pSQL _ " GROUP BY" _ tSQL2 45 | } 46 | } 47 | } 48 | quit $$$OK 49 | } 50 | 51 | /// This callback, if implemented, returns the text of an SQL query used to provide 52 | /// a "detail listing" for this KPI.
53 | /// pFilters is an array of current filter values: pFilters(name)=value.
54 | /// pSelection is an array containing information about the current selected items in the pivot. 55 | /// It contains 2 values:
56 | /// pSelection("selectedRange") contains the current selected cells in the pivot as a string in the form 57 | /// "startRow,startCol,endRow,endCol" (1-based). "" if no cells are selected.
58 | /// pSelection("rowValues") contains a csv-list of "row" values for the selected rows in the pivot (similar 59 | /// to the $$$VALUELIST value used for OpenWindow URLs. This may contain "\," for "," within the data values.
60 | /// pListingName is the name of the listing to display. This is reserved for future use.
61 | /// This method is simply a convenient alternative to the %OnGetListingResultSet method. 62 | /// It takes precedence over the %OnGetListingResultSet method. 63 | ClassMethod %OnGetListingSQL(ByRef pFilters As %String, ByRef pSelection As %String, pListingName As %String = "") As %String 64 | { 65 | set tSQL = "SELECT TOP 1000 %ID,DateOfSale,Product FROM HoleFoods.SalesTransaction" 66 | 67 | // Apply sorting, if aksed for 68 | if (+$G(pSelection("sortColumn"))>0) { 69 | set tSQL = tSQL _ " ORDER BY " _ pSelection("sortColumn") _ " " _ $G(pSelection("sortDir")) 70 | } 71 | 72 | quit tSQL 73 | } 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientAllergy.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// An allergy has multiple pieces of information, 5 | /// which you can use separately or in combination to create dimensions, depending 6 | /// on what you want to see. 7 | Class BI.Study.PatientAllergy Extends %SerialObject 8 | { 9 | 10 | /// A substance to which the patient is allergic. 11 | Property Allergen As BI.Study.Allergen; 12 | 13 | /// Severity of this allergic reaction. 14 | Property Severity As BI.Study.AllergySeverity; 15 | 16 | /// Doctor who recorded this allergic reaction. 17 | Property DiagnosedBy As BI.Study.Doctor; 18 | 19 | /// Called by BI.Study.Patient:GenerateData() or by BI.Study.PatientSet2:GenerateData(). 20 | /// Pat argument could be either BI.Study.Patient or BI.Study.PatientSet2. 21 | ClassMethod GenerateAllergies(pat, genNulls As %Boolean) As %Status 22 | { 23 | set status=$$$OK 24 | 25 | // First decide if patient has no known allergies 26 | if ##class(BI.Populate).RandomTrue(15) { 27 | // Assume ID 1 is the nil allergen 28 | set allergen=##class(BI.Study.Allergen).%OpenId(1,0) 29 | set status=..AddAllergy(pat,allergen,genNulls) 30 | quit status 31 | } 32 | 33 | // Iterate through remaining allergens and randomly assign to patient 34 | set allergencount=##class(BI.Populate).Count("BI.Study.Allergen") 35 | for i=2:1:allergencount { 36 | if ##class(BI.Populate).RandomTrue(5) { 37 | set allergen=##class(BI.Study.Allergen).%OpenId(i,0) 38 | set status=..AddAllergy(pat,allergen,genNulls) 39 | } 40 | } 41 | 42 | quit status 43 | } 44 | 45 | /// Adds the given allergen to the patient and returns the patient by reference 46 | ClassMethod AddAllergy(ByRef pat, allergen As BI.Study.Allergen, genNulls As %Boolean) As %Status 47 | { 48 | set status=$$$OK 49 | 50 | set allergy=..%New() 51 | set allergy.Allergen=allergen 52 | 53 | if (allergen.Code'="000") { 54 | 55 | set sevid=##class(BI.Populate).GetRandomId("BI.Study.AllergySeverity") 56 | set allergy.Severity=##class(BI.Study.AllergySeverity).%OpenId(sevid,0) 57 | 58 | set docid=##class(BI.Populate).GetRandomId("BI.Study.Doctor") 59 | set allergy.DiagnosedBy=##class(BI.Study.Doctor).%OpenId(docid,0) 60 | } 61 | 62 | if genNulls { 63 | // For some percent of allergies, severity is not recorded 64 | if ##class(BI.Populate).RandomTrue(2){ 65 | set allergy.Severity="" 66 | } 67 | // For some percent of allergies, diagnosing doctor is not recorded 68 | if ##class(BI.Populate).RandomTrue(8){ 69 | set allergy.DiagnosedBy="" 70 | } 71 | } 72 | 73 | // Now add this to the patient 74 | set status=pat.Allergies.Insert(allergy) 75 | 76 | // Create the same data in the PatientAllergy1 table 77 | set status=##class(BI.Study.PatientAllergy1).CreateOne(pat,allergen,allergy.Severity,allergy.DiagnosedBy) 78 | 79 | quit status 80 | } 81 | 82 | Storage Default 83 | { 84 | 85 | 86 | Allergen 87 | 88 | 89 | Severity 90 | 91 | 92 | DiagnosedBy 93 | 94 | 95 | PatientAllergyState 96 | ^BI.Study.PatientAllergyS 97 | %Storage.Serial 98 | } 99 | 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/cls/BI/Study/City.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class contains the cities and the ZIP codes to which they belong, as 5 | /// well as city-specific properties to use as level properties in BI. 6 | /// You can extend or modify the data contained here by editing the XData block in this class. 7 | Class BI.Study.City Extends %Persistent 8 | { 9 | 10 | Property PostalCode As %String; 11 | 12 | Property Name As %String; 13 | 14 | Property Population As %Integer; 15 | 16 | Property PrincipalExport As %String; 17 | 18 | /// Fields: postal code^city^city population^principal export 19 | /// There are multiple cities in most postal codes 20 | XData LoadData 21 | { 22 | 23 | 36711^Centerville^49000^video games 24 | 34577^Cypress^3000^gravel 25 | 34577^Magnolia^4503^bundt cake 26 | 34577^Pine^15060^spaghetti 27 | 38928^Cedar Falls^90000^iron 28 | 38928^Elm Heights^33194^lettuce 29 | 32006^Juniper^10333^wheat 30 | 32006^Spruce^5900^mud 31 | 32007^Redwood^29192^peaches 32 |
33 | } 34 | 35 | /// This method reads the XData block in this class and uses it to populate the table. 36 | /// This method is called by BI.Populate:GenerateData(). 37 | ClassMethod Setup() As %Status 38 | { 39 | set status=$$$OK 40 | // First kill extent and child extent 41 | // Never use %KillExtent() in a real application 42 | do ..%KillExtent() 43 | 44 | // Get a stream of XML from the XData block contained in this class 45 | set tStream=##class(%Dictionary.CompiledXData).IDKEYOpen($CLASSNAME(),"LoadData").Data 46 | if '$IsObject(tStream) {set tSC=%objlasterror quit} 47 | 48 | set status=##class(%XML.TextReader).ParseStream(tStream,.textreader) 49 | 50 | // Check status 51 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 52 | 53 | // Iterate through document, node by node 54 | while textreader.Read() 55 | { 56 | if (textreader.NodeType="chars") 57 | { 58 | set value=textreader.Value 59 | // Write !, "value is: ", value 60 | set obj=..%New() 61 | set obj.PostalCode=$Piece(value,"^",1) 62 | set obj.Name=$Piece(value,"^",2) 63 | set obj.Population=$Piece(value,"^",3) 64 | set obj.PrincipalExport=$Piece(value,"^",4) 65 | set status=obj.%Save() 66 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 67 | } 68 | } 69 | 70 | // Create an "extent set" from which we can later get random IDs 71 | set status=##class(BI.Populate).UpdateIdCache($CLASSNAME()) 72 | 73 | quit status 74 | } 75 | 76 | Storage Default 77 | { 78 | 79 | 80 | %%CLASSNAME 81 | 82 | 83 | PostalCode 84 | 85 | 86 | Name 87 | 88 | 89 | Population 90 | 91 | 92 | PrincipalExport 93 | 94 | 95 | ^BI.Study.CityD 96 | CityDefaultData 97 | ^BI.Study.CityD 98 | ^BI.Study.CityI 99 | ^BI.Study.CityS 100 | %Storage.Persistent 101 | } 102 | 103 | } 104 | 105 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/Transaction.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Instances of this class represent specific transactions within 3 | /// the HoleFoods demo.
4 | /// This table combines both "actual" data and "budget" data so that the sample cube 5 | /// can show comparisons between the two.
6 | /// Actual records will have a true value for the Actual property.
7 | /// Budget records will have a false value for the Actual property. The budget value will 8 | /// be stored in the TargetAmount property. Budget values are set for each city, product, and 9 | /// month (using the first day of the month). 10 | Class HoleFoods.Transaction Extends %Persistent [ SqlTableName = SalesTransaction ] 11 | { 12 | 13 | /// Track changes to this class. 14 | Parameter DSTIME = "auto"; 15 | 16 | Index DateOfSale On DateOfSale; 17 | 18 | Index Product On Product [ Type = bitmap ]; 19 | 20 | Index Outlet On Outlet [ Type = bitmap ]; 21 | 22 | /// If true, this represents an actual sale 23 | /// otherwise this represents a sales target. 24 | Property Actual As %Boolean; 25 | 26 | /// Date of this sale. 27 | Property DateOfSale As %Date; 28 | 29 | /// Product sold. 30 | Property Product As Product; 31 | 32 | /// Store or other outlet in which the sale occurred. 33 | Property Outlet As Outlet; 34 | 35 | /// Channel product was sold through: "Retail" or "Online". 36 | Property Channel As %String(DISPLAYLIST = ",Retail,Online", VALUELIST = ",1,2"); 37 | 38 | /// Actual amount of this sale. 39 | Property AmountOfSale As %Numeric(SCALE = 2); 40 | 41 | /// Units sold. 42 | Property UnitsSold As %Integer; 43 | 44 | /// Discount amount. 45 | Property Discount As %Numeric(SCALE = 2); 46 | 47 | /// For budget items, this is the target value for a period,region, and product. 48 | Property TargetAmount As %Numeric(SCALE = 2); 49 | 50 | /// Customer comment on this transaction (if any). 51 | Property Comment As %String(MAXLEN = 500); 52 | 53 | /// US Zipcode of customer (if provided). 54 | Property ZipCode As %String(MAXLEN = 25); 55 | 56 | /// Latitude of customer (determined from zip code). 57 | Property Latitude As %Double; 58 | 59 | /// Longitude of customer (determined from zip code). 60 | Property Longitude As %Double; 61 | 62 | Storage Default 63 | { 64 | 65 | 66 | %%CLASSNAME 67 | 68 | 69 | Actual 70 | 71 | 72 | DateOfSale 73 | 74 | 75 | Product 76 | 77 | 78 | Outlet 79 | 80 | 81 | Channel 82 | 83 | 84 | AmountOfSale 85 | 86 | 87 | UnitsSold 88 | 89 | 90 | Discount 91 | 92 | 93 | TargetAmount 94 | 95 | 96 | Comment 97 | 98 | 99 | ZipCode 100 | 101 | 102 | Latitude 103 | 104 | 105 | Longitude 106 | 107 | 108 | ^HoleFoods.TransactionD 109 | TransactionDefaultData 110 | ^HoleFoods.TransactionD 111 | ^HoleFoods.TransactionI 112 | ^HoleFoods.TransactionS 113 | %Storage.Persistent 114 | } 115 | 116 | } 117 | 118 | -------------------------------------------------------------------------------- /.github/workflows/build-push-gcr.yaml: -------------------------------------------------------------------------------- 1 | name: Cloud Run Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | 9 | env: 10 | # Change this section according to your needs 11 | IMAGE_NAME: samples-bi-demo 12 | SERVICE: samples-bi 13 | DOMAIN_NAME: samples-bi.demo.community.intersystems.com 14 | 15 | # Leave this section untouched 16 | PROJECT_ID: iris-community-demos 17 | CLUSTER_NAME: demo 18 | GITHUB_SHA: ${{ github.sha }} 19 | GCR_LOCATION: eu.gcr.io 20 | REGION: europe-west2 21 | NAMESPACE: demo 22 | 23 | jobs: 24 | deploy-cloud-run: 25 | name: Deploy to Cloud Run 26 | runs-on: ubuntu-20.04 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v2 30 | 31 | - name: Setup Cloud SDK 32 | uses: google-github-actions/setup-gcloud@v0.2.0 33 | with: 34 | version: '327.0.0' 35 | service_account_key: ${{ secrets.SERVICE_ACCOUNT_KEY }} 36 | 37 | - name: Authorize Docker push 38 | run: gcloud auth configure-docker 39 | 40 | - name: Build and Push image 41 | run: | 42 | docker build -t ${GCR_LOCATION}/${PROJECT_ID}/${IMAGE_NAME}:${GITHUB_SHA} . 43 | docker push ${GCR_LOCATION}/${PROJECT_ID}/${IMAGE_NAME}:${GITHUB_SHA} 44 | 45 | - name: Deploy to Cloud Run 46 | run: | 47 | echo "[INFO] Set google project..." 48 | gcloud config set project ${PROJECT_ID} 49 | 50 | echo "[INFO] Deploy service..." 51 | gcloud run deploy ${SERVICE} \ 52 | --platform gke \ 53 | --cluster ${CLUSTER_NAME} \ 54 | --cluster-location ${REGION} \ 55 | --namespace ${NAMESPACE} \ 56 | --port 52773 \ 57 | --min-instances 1 \ 58 | --memory 512Mi \ 59 | --timeout 300 \ 60 | --verbosity debug \ 61 | --image ${GCR_LOCATION}/${PROJECT_ID}/${IMAGE_NAME}:${GITHUB_SHA} 62 | 63 | echo "[INFO] Create domain mappings..." 64 | if [[ $(gcloud run domain-mappings list --platform gke --cluster ${CLUSTER_NAME} --cluster-location ${REGION} --namespace ${NAMESPACE} --filter "DOMAIN=${DOMAIN_NAME}" | grep -v DOMAIN | wc -l) == 0 ]]; then 65 | gcloud run domain-mappings create \ 66 | --service ${SERVICE} \ 67 | --platform gke \ 68 | --cluster ${CLUSTER_NAME} \ 69 | --cluster-location ${REGION} \ 70 | --namespace ${NAMESPACE} \ 71 | --verbosity debug \ 72 | --domain ${DOMAIN_NAME} 73 | fi 74 | 75 | - name: Create domain name 76 | run: | 77 | gcloud container clusters get-credentials ${CLUSTER_NAME} --region ${REGION} --project ${PROJECT_ID} 78 | kubectl version 79 | echo "[INFO] Checking if [${DOMAIN_NAME}] is in the existing Ingress annotation..." 80 | CURRENT_DOMAINS_LIST=$(kubectl -n gke-system get svc istio-ingress -o jsonpath="{.metadata.annotations['external-dns\.alpha\.kubernetes\.io/hostname']}") 81 | if [[ $(echo ${CURRENT_DOMAINS_LIST} | grep -w "${DOMAIN_NAME}" | wc -c) -eq 0 ]]; then \ 82 | echo "[INFO] Domain [${DOMAIN_NAME}] is ABSENT in the domains list. Adding..."; \ 83 | kubectl -n gke-system annotate --overwrite svc istio-ingress external-dns\.alpha\.kubernetes\.io/hostname=${CURRENT_DOMAINS_LIST},${DOMAIN_NAME}; \ 84 | echo -n "[INFO] Resulting domain names: " 85 | kubectl -n gke-system get svc istio-ingress -o jsonpath="{.metadata.annotations['external-dns\.alpha\.kubernetes\.io/hostname']}" 86 | else 87 | echo "[INFO] Domain [${DOMAIN_NAME}] is in the domains list. Leave untouched..."; \ 88 | fi 89 | 90 | - name: Enable TLS-access 91 | run: | 92 | gcloud container clusters get-credentials ${CLUSTER_NAME} --region ${REGION} --project ${PROJECT_ID} 93 | kubectl version 94 | kubectl patch configmap config-domainmapping -n knative-serving -p '{"data":{"autoTLS":"Enabled"}}' 95 | -------------------------------------------------------------------------------- /src/cls/BI/Study/Profession.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class contains the professions and their industries. 5 | Class BI.Study.Profession Extends %Persistent 6 | { 7 | 8 | Property Profession As %String; 9 | 10 | Property Industry As %String; 11 | 12 | /// Used by Setup method. The format of is: 13 | /// industry^profession 14 | /// Industries taken from http://www.census.gov/epcd/susb/latest/us/US--.HTM 15 | /// Only a few industries and professions are included. 16 | XData LoadData 17 | { 18 | 19 | Accommodation and Food Services^Baker 20 | Accommodation and Food Services^Cook 21 | Construction^Electrician 22 | Construction^Carpenter 23 | Construction^Plumber 24 | Educational Services^Teacher 25 | Educational Services^Corporate Trainer 26 | Finance and Insurance^Insurance Agent 27 | Finance and Insurance^Bank Teller 28 | Finance and Insurance^Benefits Coordinator 29 | Health Care and Social Assistance^Doctor 30 | Health Care and Social Assistance^Nurse 31 | Professional, Scientific, and Technical Services^Veterinarian 32 | Professional, Scientific, and Technical Services^Programmer 33 | Professional, Scientific, and Technical Services^Architect 34 | Professional, Scientific, and Technical Services^Accountant 35 | Real Estate and Leasing^Real Estate Agent 36 | Retail Trade^Retail Clerk 37 | Retail Trade^Store Manager 38 | Transportation and Warehousing^Truck Driver 39 | Transportation and Warehousing^Warehouse Manager 40 | Other Services^Appliance Repair Specialist 41 | Other Services^Other 42 |
43 | } 44 | 45 | /// This method reads the XData block in this class and uses it to populate the table. 46 | /// This method is called by BI.Populate:GenerateData(). 47 | ClassMethod Setup() As %Status 48 | { 49 | set status=$$$OK 50 | 51 | // First kill extent 52 | // Never use %KillExtent() in a real application 53 | do ..%KillExtent() 54 | 55 | // Get a stream of XML from the XData block contained in this class 56 | set tStream=##class(%Dictionary.CompiledXData).IDKEYOpen($CLASSNAME(),"LoadData").Data 57 | if '$IsObject(tStream) {set tSC=%objlasterror Quit} 58 | 59 | set status=##class(%XML.TextReader).ParseStream(tStream,.textreader) 60 | 61 | // Check status 62 | if $$$ISERR(status) {do $System.Status.DisplayError(status) Quit} 63 | 64 | set count=0 65 | 66 | // Iterate through document, node by node 67 | while textreader.Read() 68 | { 69 | if (textreader.NodeType="chars") 70 | { 71 | set value=textreader.Value 72 | // write !, "value is: ", value 73 | set obj=..%New() 74 | set obj.Industry=$Piece(value,"^",1) 75 | set obj.Profession=$Piece(value,"^",2) 76 | set status=obj.%Save() 77 | if $$$ISERR(status) {do $System.Status.DisplayError(status) Quit} 78 | set count=count+1 79 | } 80 | } 81 | 82 | // Create an "extent set" from which we can later get random IDs 83 | set status=##class(BI.Populate).UpdateIdCache($CLASSNAME()) 84 | 85 | quit status 86 | } 87 | 88 | Storage Default 89 | { 90 | 91 | 92 | %%CLASSNAME 93 | 94 | 95 | Profession 96 | 97 | 98 | Industry 99 | 100 | 101 | ^BI.Study.ProfessionD 102 | ProfessionDefaultData 103 | ^BI.Study.ProfessionD 104 | ^BI.Study.ProfessionI 105 | ^BI.Study.ProfessionS 106 | %Storage.Persistent 107 | } 108 | 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/cls/BI/Model/CompoundCube/Patients.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use in a compound cube (and can also be used on its own). 3 | /// To view the cube definition, open this class in Studio. 4 | Class BI.Model.CompoundCube.Patients Extends %DeepSee.CubeDefinition [ DependsOn = BI.Study.Patient ] 5 | { 6 | 7 | Parameter DOMAIN = "PATIENTSAMPLE"; 8 | 9 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 10 | { 11 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 41 | 44 | 49 | 50 | 51 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | 62 | 64 | 65 | 69 | 73 | 76 | 79 | 80 | 81 | 82 | 83 | 87 | 88 | 91 | 92 | 95 | 96 | 98 | 99 | 100 | } 101 | 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/cls/BI/Model/PortletDemo/svgClock.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | Class BI.Model.PortletDemo.svgClock Extends %CSP.Page 3 | { 4 | 5 | ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ] 6 | { 7 | set %response.ContentType="image/svg+xml" 8 | quit $$$OK 9 | } 10 | 11 | ClassMethod OnPage() As %Status 12 | { 13 | set size=$G(%request.Data("SIZE",1),200) 14 | set uri="?" 15 | for par="LOGO","CIRCLE","UTC","OFFSET","STEP" { 16 | if $d(%request.Data(par,1),val) set uri=uri_par_"="_val_"&" 17 | } 18 | &html< 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 63 | > 64 | write " 68 | 122 | 123 | > 124 | quit $$$OK 125 | } 126 | 127 | } 128 | 129 | -------------------------------------------------------------------------------- /src/cls/BI/Model/RelCubes/RPatients.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is for use with InterSystems IRIS BI. 3 | /// It contains a cube based on BI.Study.Patients. 4 | /// To view the cube definition, open this class in Studio or the BI Architect. 5 | /// The RelatedCubes/* cubes (like this one) use cube-to-cube relationships. 6 | Class BI.Model.RelCubes.RPatients Extends %DeepSee.CubeDefinition [ DependsOn = (BI.Study.Patient, BI.Model.RelCubes.RDoctors, BI.Model.RelCubes.RCities) ] 7 | { 8 | 9 | Parameter DOMAIN = "PATIENTSAMPLE"; 10 | 11 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 12 | { 13 | 20 | 21 | 25 | 26 | 30 | 31 | 35 | 36 | 38 | 39 | 43 | 46 | 49 | 53 | 54 | 55 | 56 | 57 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 84 | 85 | 86 | 87 | 88 | 89 | 92 | 93 | 94 | 95 | 96 | 97 | 100 | 103 | 104 | 105 | 106 | 109 | 110 | 114 | 115 | 118 | 119 | 122 | 123 | 124 | } 125 | 126 | } 127 | 128 | -------------------------------------------------------------------------------- /src/cls/BI/Study/CityRainfall.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class contains the rainfall for the cities, by year and month, and is meant 5 | /// for use as an additional BI model/cube. 6 | /// This table is populated only if you use the R option when running the 7 | /// GenerateData() method in BI.Populate. You can also use 8 | /// the GenerateData() method in this class if you have already populated the main 9 | /// sample. 10 | /// You can extend or modify the data contained here by editing the XData block in this class. 11 | Class BI.Study.CityRainfall Extends %Persistent 12 | { 13 | 14 | /// This parameter setting enables the DSTIME feature for InterSystems IRIS BI 15 | Parameter DSTIME = "AUTO"; 16 | 17 | Property City As BI.Study.City; 18 | 19 | Property MonthAndYear As %Date; 20 | 21 | Property InchesOfRain As %Numeric; 22 | 23 | /// Fields: month number^average rainfall in inches^variance in inches 24 | XData LoadData 25 | { 26 | 27 | 1^1.13^0.25 28 | 2^1.56^0.25 29 | 3^2.71^0.25 30 | 4^2.77^0.5 31 | 5^5.22^0.5 32 | 6^4.31^0.5 33 | 7^2.61^0.35 34 | 8^2.60^0.35 35 | 9^3.84^0.5 36 | 10^3.23^0.5 37 | 11^1.98^0.35 38 | 12^1.40^0.25 39 |
40 | } 41 | 42 | /// Call this after the cities have been set up; this means we reopen each city once. 43 | ClassMethod GenerateData() As %Status 44 | { 45 | write !, "Creating rainfall data for the cities..." 46 | 47 | // Never use %KillExtent() in a real application 48 | do ..%KillExtent() 49 | 50 | // Get a stream of XML from the XData block contained in this class 51 | set tStream=##class(%Dictionary.CompiledXData).IDKEYOpen($CLASSNAME(),"LoadData").Data 52 | if '$IsObject(tStream) {set tSC=%objlasterror quit} 53 | 54 | set status=##class(%XML.TextReader).ParseStream(tStream,.textreader) 55 | //check status 56 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 57 | 58 | //iterate through document, node by node 59 | while textreader.Read() 60 | { 61 | if (textreader.NodeType="chars") 62 | { 63 | set value=textreader.Value 64 | 65 | set month=$Piece(value,"^",1) 66 | set avgrainfall=$Piece(value,"^",2) 67 | set var=$Piece(value,"^",3) 68 | set ^||myvar("rainfall",month,"min")=avgrainfall-var 69 | set ^||myvar("rainfall",month,"max")=avgrainfall+var 70 | } 71 | } 72 | 73 | set myquery="select ID from BI_Study.City" 74 | set rset=##class(%ResultSet).%New("%DynamicQuery:SQL") 75 | set status=rset.Prepare(myquery) 76 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 77 | set status=rset.Execute() 78 | 79 | while (rset.Next(.status)) { 80 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 81 | set cityid=rset.Data("ID") 82 | set city=##class(BI.Study.City).%OpenId(cityid,0) 83 | 84 | //we have rainfall data for a particular span of years 85 | set separator=##class(%SYS.NLS.Format).GetFormatItem("DateSeparator") 86 | for year=1900:1:$Piece($Zdate($h,1),separator,3) { 87 | for month=1:1:12 { 88 | set record=..%New() 89 | set record.City=city 90 | if (month<10) { 91 | set monthstring="0"_month 92 | } 93 | else { 94 | set monthstring=month 95 | } 96 | set datestring=year_"-"_monthstring_"-01" 97 | set min=^||myvar("rainfall",month,"min") 98 | set max=^||myvar("rainfall",month,"max") 99 | set rainfall=min + ($RANdoM(max*100)+1)/100 100 | 101 | 102 | set record.MonthAndYear=$ZDATEH(datestring,3) 103 | set record.InchesOfRain=rainfall 104 | set status=record.%Save() 105 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 106 | } 107 | } 108 | 109 | } 110 | 111 | do ##class(%DeepSee.Utils).%SynchronizeCube("cityrainfall") 112 | 113 | quit status 114 | } 115 | 116 | Storage Default 117 | { 118 | 119 | 120 | %%CLASSNAME 121 | 122 | 123 | City 124 | 125 | 126 | MonthAndYear 127 | 128 | 129 | InchesOfRain 130 | 131 | 132 | ^BI.Study.CityRainfallD 133 | CityRainfallDefaultData 134 | ^BI.Study.CityRainfallD 135 | ^BI.Study.CityRainfallI 136 | ^BI.Study.CityRainfallS 137 | %Storage.Persistent 138 | } 139 | 140 | } 141 | 142 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/KPISalesVsTarget.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Sample KPI for HoleFoods Demo. 3 | /// This KPI provides real sales data compared with budget targets. 4 | Class HoleFoods.KPISalesVsTarget Extends %DeepSee.KPI 5 | { 6 | 7 | /// Used to pass ROWS clause among methods. 8 | Property RowClause As %String; 9 | 10 | /// Used to pass filter clause among methods. 11 | Property FilterClause As %String; 12 | 13 | /// This XData definition defines the KPI. 14 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 15 | { 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | } 29 | 30 | /// Notification that this KPI is being executed. 31 | /// This is a good place to override properties, such as range and threshold. 32 | Method %OnLoadKPI() As %Status 33 | { 34 | set tSC = $$$OK 35 | 36 | // Compute additional values 37 | set tFilters = ..%filterValues 38 | 39 | // Compute recent history using query 40 | if ((tFilters.Year'="")&&(tFilters.Year'="*")&&(tFilters.Year'="&[NOW]")) { 41 | // Take &[] off of Year value! 42 | set tStartMonth = "Jan-"_$E(tFilters.Year,3,6) 43 | set tEndMonth = "Dec-"_$E(tFilters.Year,3,6) 44 | } 45 | else { 46 | set tStartMonth = "NOW-12" 47 | set tEndMonth = "NOW" 48 | } 49 | 50 | set tROWS = ..RowsClause 51 | set tMDX = "SELECT "_tROWS_"%LIST(DateOfSale.[MonthSold].["_tStartMonth_"]:["_tEndMonth_"]) ON COLUMNS FROM HOLEFOODSCOMBINED WHERE Measures.[Amount Sold] " _ ..FilterClause 52 | set tRS = ##class(%DeepSee.ResultSet).%New() 53 | set tSC = tRS.%PrepareMDX(tMDX) 54 | if $$$ISERR(tSC) quit tSC 55 | set tSC = tRS.%Execute() 56 | if $$$ISERR(tSC) quit tSC 57 | 58 | for n = 1:1:..%seriesCount { 59 | set tValue = tRS.%GetOrdinalValue(1,n) 60 | set ..%data(n,"History") = tValue 61 | } 62 | quit tSC 63 | } 64 | 65 | /// Return an MDX statement to execute. 66 | Method %OnGetMDX(ByRef pMDX As %String) As %Status 67 | { 68 | set tFilters = ..%filterValues 69 | 70 | // Construct an MDX query based on the current filter values 71 | set tROWS = "" 72 | set tFILTER = "" 73 | 74 | // Show by 75 | if (tFilters.ShowBy="Year") { 76 | set tROWS = "[DateOfSale].[YearSold].Members" 77 | } 78 | elseif (tFilters.ShowBy="Month") { 79 | set tROWS = "[DateOfSale].[MonthSold].Members" 80 | } 81 | elseif ((tFilters.ShowBy="ProductCategory")) { 82 | set tROWS = "[Product].[Product Category].Members" 83 | } 84 | elseif ((tFilters.ShowBy="ProductName")||(tFilters.ShowBy="")) { 85 | set tROWS = "[Product].[Product Name].Members" 86 | } 87 | elseif (tFilters.ShowBy="Country") { 88 | set tROWS = "[Outlet].[Country].Members" 89 | } 90 | elseif (tFilters.ShowBy="City") { 91 | set tROWS = "[Outlet].[City].Members" 92 | } 93 | 94 | if (tROWS'="") { 95 | set tROWS = "NON EMPTY "_tROWS_" ON ROWS," 96 | } 97 | 98 | // Filters 99 | if ((tFilters.Year'="")&&(tFilters.Year'="*")) { 100 | set tFILTER = tFILTER_" %FILTER [DateOfSale].[YearSold]."_tFilters.Year 101 | } 102 | if ((tFilters.Product'="")&&(tFilters.Product'="*")) { 103 | set tFILTER = tFILTER_" %FILTER [Product].[Product Category]."_tFilters.Product 104 | } 105 | if ((tFilters.Country'="")&&(tFilters.Country'="*")) { 106 | set tFILTER = tFILTER_" %FILTER [Outlet].[Country]."_tFilters.Country 107 | } 108 | 109 | set ..FilterClause = tFILTER 110 | set ..RowsClause = tROWS 111 | 112 | set pMDX = "SELECT "_tROWS_"{Measures.[Amount Sold],Measures.[Target]} ON Columns FROM HOLEFOODSCOMBINED "_tFILTER 113 | quit $$$OK 114 | } 115 | 116 | /// Callback to get additional members for a KPI filter. 117 | /// This takes the form:
118 | /// pMembers($I(pMembers))=$LB(text,value)
119 | ClassMethod %OnGetFilterMembers(pFilter As %String, Output pMembers As %List, pSearchKey As %String) As %Status 120 | { 121 | set tSC = $$$OK 122 | try { 123 | // Get member list from cube 124 | if (pFilter = "Year") { 125 | set tSC = ..%GetMembersForFilter("HOLEFOODSCOMBINED","[DateOfSale].[Actual].[YearSold]",.pMembers,pSearchKey) 126 | if $$$ISERR(tSC) quit 127 | } 128 | elseif (pFilter = "Product") { 129 | set tSC = ..%GetMembersForFilter("HOLEFOODSCOMBINED","[Product].[P1].[Product Name]",.pMembers,pSearchKey) 130 | if $$$ISERR(tSC) quit 131 | } 132 | elseif (pFilter = "Country") { 133 | set tSC = ..%GetMembersForFilter("HOLEFOODSCOMBINED","[Outlet].[H1].[Country]",.pMembers,pSearchKey) 134 | if $$$ISERR(tSC) quit 135 | } 136 | } 137 | catch(ex) { 138 | set tSC = ex.AsStatus() 139 | } 140 | quit tSC 141 | } 142 | 143 | } 144 | 145 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/KPICFO.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Sample KPI for HoleFoods Demo. 3 | /// This KPI provides synthetic corporate data and defines some simple actions. 4 | Class HoleFoods.KPICFO Extends %DeepSee.KPI 5 | { 6 | 7 | /// This XData definition defines the KPI. 8 | XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ] 9 | { 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | } 22 | 23 | /// Notify subclass that KPI is has just be executed. 24 | /// This is a good place to override properties, such as range and threshold. 25 | Method %OnLoadKPI() As %Status 26 | { 27 | // Define list of metrics we will calculate 28 | // all are percentage of target, so are 0-1.5 typically. 29 | 30 | set tMetrics(1) = "EBIT" 31 | set tMetrics(2) = "Share Price" 32 | set tMetrics(3) = "A/Payable" 33 | set tMetrics(4) = "A/Receivable" 34 | set tMetrics(5) = "Long-term Debt" 35 | set tMetrics(6) = "Inventory" 36 | set tMetrics(7) = "Market Share" 37 | 38 | set ..%seriesCount = 0 39 | set n = $O(tMetrics("")) 40 | while (n'="") { 41 | set ..%seriesCount = ..%seriesCount + 1 42 | set ..%seriesNames(n) = $G(tMetrics(n)) 43 | set ..%data(n,"Metric") = $G(^HoleFoods.CFO(n)) 44 | set tDelta = $G(^HoleFoods.CFO(n,"delta")) 45 | set ..%data(n,"Trend") = $S(tDelta>0.05:tDelta,tDelta<-0.05:tDelta,1:0) 46 | 47 | set tLow = 0.5 48 | set tHigh = 0.8 49 | if (n=2) { 50 | // Special case for share price 51 | set tLow = 0.8 52 | set tHigh = 1.2 53 | } 54 | 55 | if (..%data(n,"Metric") < tLow) { 56 | set ..%data(n,"Alarm") = (tLow-..%data(n,"Metric"))*-100 57 | } 58 | elseif (..%data(n,"Metric") > tHigh) { 59 | set ..%data(n,"Alarm") = (..%data(n,"Metric")-tHigh)*100 60 | } 61 | else { 62 | set ..%data(n,"Alarm") = 0 63 | } 64 | set n = $O(tMetrics(n)) 65 | } 66 | quit $$$OK 67 | } 68 | 69 | /// This callback is invoked from a dashboard when an action defined by this dashboard is invoked. 70 | ClassMethod %OnDashboardAction(pAction As %String, pContext As %ZEN.proxyObject) As %Status 71 | { 72 | #define EBIT 1 73 | #define SHARE 2 74 | #define AR 3 75 | #define AP 4 76 | #define DEBT 5 77 | #define INV 6 78 | #define MKT 7 79 | 80 | #define INCREASE(%n,%amt) set ^HoleFoods.CFO(%n) = ($G(^HoleFoods.CFO(%n)) * (1 + (($R(%amt)-(%amt*0.25))/100))) 81 | #define DECREASE(%n,%amt) set ^HoleFoods.CFO(%n) = ($G(^HoleFoods.CFO(%n)) * (1 + (($R(%amt)-(%amt*0.75))/100))) 82 | 83 | // Remember prior value so we can compute delta 84 | merge tPrior = ^HoleFoods.CFO 85 | 86 | if (pAction = "Spend") { 87 | $$$DECREASE($$$EBIT,40) 88 | $$$INCREASE($$$AP,40) 89 | $$$DECREASE($$$AR,5) 90 | $$$INCREASE($$$DEBT,30) 91 | $$$INCREASE($$$INV,20) 92 | $$$INCREASE($$$MKT,5) 93 | set pContext.command = "refresh" 94 | } 95 | elseif (pAction = "Cut Costs") { 96 | $$$INCREASE($$$EBIT,40) 97 | $$$DECREASE($$$AP,30) 98 | $$$INCREASE($$$AR,5) 99 | $$$DECREASE($$$DEBT,5) 100 | $$$DECREASE($$$INV,10) 101 | $$$DECREASE($$$MKT,5) 102 | set pContext.command = "refresh" 103 | } 104 | elseif (pAction = "Raise Prices") { 105 | $$$INCREASE($$$EBIT,20) 106 | $$$INCREASE($$$AR,30) 107 | $$$DECREASE($$$DEBT,10) 108 | $$$INCREASE($$$INV,10) 109 | $$$DECREASE($$$MKT,10) 110 | set pContext.command = "refresh" 111 | } 112 | elseif (pAction = "Cut Prices") { 113 | $$$DECREASE($$$EBIT,40) 114 | $$$DECREASE($$$AR,30) 115 | $$$INCREASE($$$DEBT,10) 116 | $$$DECREASE($$$INV,30) 117 | $$$INCREASE($$$MKT,10) 118 | set pContext.command = "refresh" 119 | } 120 | elseif (pAction = "Reset") { 121 | kill ^HoleFoods.CFO 122 | set ^HoleFoods.CFO(1) = 0.8 123 | set ^HoleFoods.CFO(2) = 0.6 124 | set ^HoleFoods.CFO(3) = 0.8 125 | set ^HoleFoods.CFO(4) = 0.8 126 | set ^HoleFoods.CFO(5) = 0.8 127 | set ^HoleFoods.CFO(6) = 0.8 128 | set ^HoleFoods.CFO(7) = 0.5 129 | 130 | // Send refresh command to client 131 | set pContext.command = "refresh" 132 | } 133 | 134 | if ($G(^HoleFoods.CFO($$$MKT)) > 0.95) { 135 | // No monopolies 136 | set ^HoleFoods.CFO($$$MKT) = 0.95 137 | } 138 | 139 | 140 | // Share price is average of all! 141 | // but each "zero" takes away points 142 | set tTotal = 0 143 | set tCount = 0 144 | set tZeroes = 0 145 | set n = $O(^HoleFoods.CFO("")) 146 | while (n'="") { 147 | set tValue = $G(^HoleFoods.CFO(n)) 148 | if (tValue <= 0) { 149 | set ^HoleFoods.CFO(n) = 0 150 | } 151 | if (tValue < 0.2) { 152 | set tZeroes = tZeroes + 1 153 | } 154 | if (tValue >= 1.5) { 155 | set ^HoleFoods.CFO(n) = 1.5 156 | } 157 | set tCount = tCount + 1 158 | set tTotal = tTotal + tValue 159 | set n = $O(^HoleFoods.CFO(n)) 160 | } 161 | if (tCount>0) { 162 | set ^HoleFoods.CFO($$$SHARE) = (tTotal/tCount) / (tZeroes+1) 163 | if (^HoleFoods.CFO($$$SHARE)<=0) { 164 | // Out of business 165 | set ^HoleFoods.CFO($$$SHARE) = 0 166 | } 167 | } 168 | 169 | // Compute deltas, if any 170 | set n = $O(tPrior("")) 171 | while (n'="") { 172 | set tOld = $G(tPrior(n)) 173 | if (tOld'="") { 174 | set ^HoleFoods.CFO(n,"delta") = $G(^HoleFoods.CFO(n)) - tOld 175 | } 176 | set n = $O(tPrior(n)) 177 | } 178 | 179 | quit $$$OK 180 | } 181 | 182 | } 183 | 184 | -------------------------------------------------------------------------------- /src/cls/BI/Study/Diagnosis.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | ///

This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class contains the diagnosis code lookup table, with a small set of possible 5 | /// diagnoses. It also defines the incidence rates for these diagnoses, by age and gender. 6 | /// You can extend or modify the data contained here by editing the XData block in this class. 7 | /// Use the GetPercentChance() method to retrieve the chance of having 8 | /// a specific diagnosis, given an age and gender. 9 | Class BI.Study.Diagnosis Extends %Persistent 10 | { 11 | 12 | /// Unique code for the diagnosis; 13 | Property Code As %String; 14 | 15 | /// Unique description (user-visible name) for the diagnosis 16 | Property Description As %String; 17 | 18 | /// A row element is a pieced string with the following format: 19 | ///

diagnosis code^diagnosis description^fpiece^mpiece 
20 | /// fpiece gives rates for females, and mpiece gives rates for males. 21 | /// Both fpiece and mpiece have the following format: 22 | ///
bucket1 details,bucket2 details,bucket3 details, ... 
23 | /// Each bucket represents an age bucket and the number of current (not lifetime) 24 | /// diagnoses of this type per hundred patients of this age and gender. 25 | /// Each bucket has the following format: 26 | ///
lowerAge_upperAge_countPerHundredPatientsOfThisAgeAndGender
27 | /// Each row must have data for all ages for patients of either gender. 28 | /// Asthma source: ASTHMA06FINAL.PDF from www.lungusa.org/atf/cf/ 29 | /// CHD: www.heartstats.org (used numbers for 1998) 30 | /// Diabetes: www.mchd.com/data_reports/mccha/12_Morbidity_and_Hospitalizations.html (Used U.S. values) 31 | /// Osteoporosis source: http://www.surgeongeneral.gov/library/bonehealth/ (No data for patients under 65) 32 | /// Epilepsy: wikipedia (55 cases per 100000 people) 33 | XData LoadData 34 | { 35 | 36 | diabetes^diabetes 37 | ^0_17_0, 18_24_1.5, 25_34_3.2, 35_44_5.2, 45_54_7.9, 55_64_13.4, 65_999_17.1 38 | ^0_17_0, 18_24_1.5, 25_34_3.2, 35_44_5.2, 45_54_7.9, 55_64_13.4, 65_999_17.1 39 | 40 | asthma^asthma 41 | ^0_17_06.71, 18_999_8.25 42 | ^0_17_10.15, 18_999_4.97 43 | 44 | CHD^coronary heart disease 45 | ^0_15_0, 16_24_0, 25_34_.3, 35_44_.6, 45_54_1.8, 55_64_6.3, 65_74_12.5, 75_999_18.4 46 | ^0_15_0, 16_24_.1, 25_34_.4, 35_44_.9, 45_54_4.3, 55_64_13.6, 65_74_20.2, 75_999_23.4 47 | 48 | osteoporosis^osteoporosis 49 | ^0_64_0, 65_74_19.0, 75_84_32.5, 85_999_50.5 50 | ^0_64_0, 65_74_02.0, 75_84_06.4, 85_999_13.7 51 | 52 | epilepsy^epilepsy 53 | ^0_999_.00055 54 | ^0_999_.00055 55 | 56 |
57 | } 58 | 59 | /// This method reads the XData block in this class and uses it to populate the table. 60 | /// This method is called by BI.Populate:GenerateData(). 61 | /// It also writes related data to a global for use when creating patients. 62 | /// The diagnosis incidence rates are deliberately NOT put into a table where 63 | /// BI can access them. The idea of the sample is to simulate real-life 64 | /// patterns. 65 | ClassMethod Setup() As %Status 66 | { 67 | set status=$$$OK 68 | 69 | // First kill extent and related global 70 | // Never use %KillExtent() in a real application 71 | do ..%KillExtent() 72 | kill ^BI.Study.SetupData("diagnoses") 73 | 74 | // Get a stream of XML from the XData block contained in this class 75 | set tStream=##class(%Dictionary.CompiledXData).IDKEYOpen($CLASSNAME(),"LoadData").Data 76 | if '$IsObject(tStream) {set tSC=%objlasterror quit} 77 | 78 | set status=##class(%XML.TextReader).ParseStream(tStream,.textreader) 79 | 80 | // Check status 81 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 82 | 83 | // Iterate through document, node by node 84 | while textreader.Read() 85 | { 86 | if (textreader.NodeType="chars") 87 | { 88 | set value=textreader.Value 89 | set obj=..%New() 90 | set diagcode=$Piece(value,"^",1) ;use this below in multiple places 91 | set obj.Code=diagcode 92 | set obj.Description=$Piece(value,"^",2) 93 | set status=obj.%Save() 94 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 95 | 96 | // Now set global to contain occurrence rates by gender and age 97 | set fpiece=$ZSTRIP($Piece(value,"^",3),"*CW") ; strip out line feed & white space 98 | set mpiece=$ZSTRIP($Piece(value,"^",4),"*CW") ; strip out line feed & white space 99 | 100 | set ^BI.Study.SetupData("diagnoses",diagcode,"F")=fpiece 101 | set ^BI.Study.SetupData("diagnoses",diagcode,"M")=mpiece 102 | } 103 | 104 | } 105 | 106 | quit status 107 | } 108 | 109 | /// For use when generating data; called by Setup method. 110 | /// Can also use this at the command line for testing purposes. 111 | ClassMethod GetPercentChance(code As %String, gender As %String, age As %Numeric) As %Numeric 112 | { 113 | // Get appropriate global node & convert it to a list 114 | set list=$LISTFROMSTRING(^BI.Study.SetupData("diagnoses",code,gender)) 115 | 116 | set chance=0 117 | // Iterate through list and find appropriate bucket 118 | for i=1:1:$LISTLENGTH(list) { 119 | // Get list item and its upper and lower ages 120 | set item=$LISTGET(list,i) 121 | set itemlowerage=+$Piece(item,"_",1) 122 | set itemupperage=+$Piece(item,"_",2) 123 | 124 | if ((age>itemlowerage) && (age<=itemupperage)) { 125 | set chance=$Piece(item,"_",3) 126 | } 127 | } 128 | 129 | quit chance 130 | } 131 | 132 | Storage Default 133 | { 134 | 135 | 136 | %%CLASSNAME 137 | 138 | 139 | Code 140 | 141 | 142 | Description 143 | 144 | 145 | ^BI.Study.DiagnosisD 146 | DiagnosisDefaultData 147 | ^BI.Study.DiagnosisD 148 | ^BI.Study.DiagnosisI 149 | ^BI.Study.DiagnosisS 150 | %Storage.Persistent 151 | } 152 | 153 | } 154 | 155 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientDetails.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// It represents an additional table of data, 5 | /// perhaps entered by a separate research team, and its only connection to 6 | /// BI.Study.Patient is that both tables have the same PatientID field. Thus to use 7 | /// fields of this table as BI dimensions/levels, it is necessary to use an SQL query 8 | /// in the dimension definition. 9 | /// This table is populated only if you use the T option when running the 10 | /// GenerateData() method in BI.Populate. 11 | Class BI.Study.PatientDetails Extends %Persistent 12 | { 13 | 14 | Property PatientID As %String; 15 | 16 | Property Profession As BI.Study.Profession; 17 | 18 | Property FavoriteColor As %String; 19 | 20 | /// This index is meant to improve performance when the BI indices are built. 21 | /// The BI data model for BI.Study.Patient uses an SQL query that refers 22 | /// to PatientID. 23 | Index PatientIDIndex On PatientID [ Unique ]; 24 | 25 | /// Called by BI.Study.Patient:AddPatients(). 26 | ClassMethod CreatePatientDetails(PatientID As %String, age As %Numeric = 35, genNulls As %Boolean) As %Status 27 | { 28 | set status=$$$OK 29 | set patdetails=##class(PatientDetails).%New() 30 | set patdetails.PatientID=PatientID 31 | 32 | // Get random color 33 | set colorlist=$LB("Red","Blue","Green","Purple","Yellow","Orange") 34 | set colorid=$RANDOM($LISTLENGTH(colorlist))+1 35 | set patdetails.FavoriteColor=$LI(colorlist,colorid) 36 | 37 | if ((age>17) && (age<70)) 38 | { 39 | // Not everyone in this age range is employed 40 | if ##class(BI.Populate).RandomTrue(87){ 41 | // Get random profession 42 | set profid=##class(BI.Populate).GetRandomId("BI.Study.Profession") 43 | set patdetails.Profession=##class(BI.Study.Profession).%OpenId(profid,0) 44 | } 45 | } 46 | 47 | if 'genNulls 48 | { 49 | // If genNulls is off, save details in all cases 50 | set status=patdetails.%Save() 51 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Write !, "Details error"} 52 | } 53 | Else 54 | { 55 | // If genNulls is on, roll the dice and 56 | // save the details only some of the time 57 | if ##class(BI.Populate).RandomTrue(76) 58 | { 59 | set status=patdetails.%Save() 60 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Write !, "Patient details save error"} 61 | } 62 | } 63 | 64 | quit status 65 | } 66 | 67 | /// Iterate through patient extent and change color for some percentage of patients. 68 | /// If rebuild is 1, this method updates the BI indices for each patient 69 | /// affected by these changes. 70 | ClassMethod ChangePatientDetails(percent As %Numeric = 10, rebuild As %Boolean = 1) 71 | { 72 | set ^BI.Study.Log($I(^BI.Study.Log))=$zdatetime($h,2,3)_" Changing some patient details..." 73 | 74 | // Create or update the "ID extent sets" from which we can later get random IDs 75 | set status=##class(BI.Populate).UpdateIdCache($CLASSNAME()) 76 | 77 | set recordcount=##class(BI.Populate).Count($CLASSNAME()) 78 | set changecount=0 79 | 80 | set colorlist=$LB("Red","Blue","Green","Purple","Yellow","Orange") 81 | 82 | for i=1:1:recordcount 83 | { 84 | if ##class(BI.Populate).RandomTrue(percent) 85 | { 86 | set colorid=$RANDOM($LISTLENGTH(colorlist))+1 87 | 88 | set randomid=##class(BI.Populate).GetRandomId($CLASSNAME()) 89 | set patdetails=..%OpenId(randomid) 90 | set patdetails.FavoriteColor=$LI(colorlist,colorid) 91 | do patdetails.%Save() 92 | set changecount=changecount+1 93 | 94 | if rebuild { 95 | // Because the BI.Study.Patient table is unaware of the BI.Study.PatientDetails 96 | // table, changing info in PatientDetails does NOT fire any triggers for 97 | // the patients, so it is necessary to figure out which patients are 98 | // affected and update the indices for those patients 99 | 100 | set patID=patdetails.PatientID 101 | 102 | set myquery="SELECT ID FROM BI_Study.Patient WHERE PatientID=?" 103 | set rset=##class(%ResultSet).%New("%DynamicQuery:SQL") 104 | set status=rset.Prepare(myquery) 105 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) quit} 106 | set status=rset.Execute(patID) 107 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) quit} 108 | while rset.Next() { 109 | set id=rset.Data("ID") 110 | 111 | do ##class(%DeepSee.Utils).%ProcessFact("patients",id) 112 | 113 | } 114 | kill rset 115 | 116 | } 117 | } 118 | } 119 | if rebuild {kill %this} ; needed because zzBuildOne doesn't clean this up 120 | set ^BI.Study.Log($I(^BI.Study.Log))=$zdatetime($h,2,3)_" Details changed for "_ changecount _" patients" 121 | } 122 | 123 | /// Clear out patient details 124 | ClassMethod DeletePatientDetails(PatientID As %String) As %Status 125 | { 126 | 127 | set myquery="DELETE FROM BI_Study.PatientDetails WHERE PatientID=?" 128 | set rset=##class(%ResultSet).%New("%DynamicQuery:SQL") 129 | set status=rset.Prepare(myquery) 130 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) quit} 131 | set status=rset.Execute(PatientID) 132 | quit status 133 | } 134 | 135 | Storage Default 136 | { 137 | 138 | 139 | %%CLASSNAME 140 | 141 | 142 | PatientID 143 | 144 | 145 | Profession 146 | 147 | 148 | FavoriteColor 149 | 150 | 151 | ^BI.Study.PatientDetailsD 152 | PatientDetailsDefaultData 153 | ^BI.Study.PatientDetailsD 154 | ^BI.Study.PatientDetailsI 155 | ^BI.Study.PatientDetailsS 156 | %Storage.Persistent 157 | } 158 | 159 | } 160 | 161 | -------------------------------------------------------------------------------- /src/cls/BI/Utils/MDXAutoFiltersKPI.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// Use this superclass to create an MDX-based KPI that automatically 3 | /// adds a %FILTER clause to your MDX query. The %FILTER clause includes 4 | /// any selections in any filters that use levels from the appropriate cube. 5 | /// To use this superclass: 6 | /// Specify sourceType="mdx" in <kpi>. 7 | /// Specify a query within the mdx attribute of <kpi> 8 | /// Specify the CUBE parameter so that we can automatically fetch the members 9 | /// of the levels for use as filters. 10 | /// Instead, all levels of the associated cube are automatically available as filters. 11 | /// Or, if you want more control over the form of the query, override %OnGetMDX() as usual 12 | /// and include the following line after creating your basic MDX query: 13 | /// set pMDX=pMDX_..FilterBuilder() 14 | /// This method gets the current filter state, creates the %FILTER clause, 15 | /// and tacks it on to the end of your query. 16 | /// If you want more control over the members of one or more filters, override 17 | /// %OnGetFilterMembers() as usual. To get all the members for a given level/filter, 18 | /// use this: set sc=..%GetMembersForFilter(..#CUBE,pFilter,.pMembers) 19 | /// And then do something different as needed in other scenarios. 20 | /// To add additional filters (to be used in a different way): 21 | /// Within , declare the filters that you want to make available. 22 | /// The logical name for each filter must be of the form of an MDX level specifier, e.g., 23 | /// [dimension].[hierarchy].[level]. This is needed so that we can retrieve the 24 | /// level members. 25 | /// Override %OnGetFilters(). In your implementation, get the filters from the 26 | /// cube by calling #super() and then add your custom filters to the array. 27 | Class BI.Utils.MDXAutoFiltersKPI Extends %DeepSee.KPI [ Abstract ] 28 | { 29 | 30 | /// Specifies the cube that this KPI uses. Specify the logical cube name. 31 | Parameter CUBE As %String; 32 | 33 | /// Implementation; can be overridden. 34 | ClassMethod %OnGetFilterMembers(pFilter As %String, Output pMembers As %List, pSearchKey As %String = "", pDataSourceName As %String = "") As %Status 35 | { 36 | set sc=..%GetMembersForFilter(..#CUBE_".cube",pFilter,.pMembers) 37 | quit sc 38 | } 39 | 40 | /// Implementation; can be overridden. 41 | Method %OnGetMDX(ByRef pMDX As %String) As %Status 42 | { 43 | set pMDX=pMDX_..FilterBuilder() 44 | quit $$$OK 45 | } 46 | 47 | /// Examines the filters defined in the cube, determines the current value of each, 48 | /// returns a string that can be used as the %FILTER clause. 49 | Method FilterBuilder() As %String [ Internal, Private ] 50 | { 51 | set tFilters="" 52 | set tSC = ##class(%DeepSee.Dashboard.Utils).%GetFiltersForDataSource(..#CUBE_".cube",.tFilters) 53 | quit:$$$ISERR(tSC) "" 54 | 55 | // Iterate through defined filters and build up usedFilters array 56 | set i = "",usedFilters=0 57 | for { 58 | set i = $order(tFilters(i)) 59 | quit:i="" 60 | 61 | set filter=tFilters(i) 62 | set filterName=$LI(filter,2) 63 | set filterValue=$PROPERTY(..%filterValues,filterName) 64 | 65 | if filterValue'="" { 66 | set usedFilters=usedFilters+1 67 | do ..ParseFilterValue(filterValue,.FilterStateArray) 68 | // create usedFilters array 69 | //used FilterStateArray and build the string for this filter 70 | set string=..BuildString(filterName,.FilterStateArray) 71 | set usedFilters(usedFilters)=string 72 | } ; end of looking at non-null filters 73 | 74 | } ; end of looking at defined filters 75 | 76 | set where="" 77 | if usedFilters>=1 { 78 | set where=..CombineFilterStrings(.usedFilters) 79 | } 80 | quit where 81 | } 82 | 83 | /// Uses usedFilters array and returns a string that can be used 84 | /// as the %FILTER clause of a MDX query. 85 | ClassMethod CombineFilterStrings(ByRef usedFilters) As %String [ Private ] 86 | { 87 | set where="" 88 | if (usedFilters=1) { 89 | set where=" %FILTER "_usedFilters(1) 90 | } elseif (usedFilters>1) { 91 | set where=usedFilters(1) 92 | for i=2:1:usedFilters { 93 | set where="NONEMPTYCROSSJOIN("_usedFilters(i)_","_where_")" 94 | } 95 | set where=" %FILTER "_where 96 | } 97 | quit where 98 | } 99 | 100 | /// Given a filter value, returns, by reference, a FilterStateArray, 101 | /// which describes the filter state. 102 | ClassMethod ParseFilterValue(filterValue As %String, Output FilterStateArray) As %Status [ Private ] 103 | { 104 | // Initialize this node 105 | kill FilterStateArray 106 | set FilterStateArray("not")=0 107 | 108 | Set filterValue = $ZSTRIP(filterValue,"<>W") 109 | set firstbit=$EXTRACT(filterValue,1,4) 110 | if firstbit="%NOT" { 111 | set FilterStateArray("not")=1 112 | set filterValue=$EXTRACT(filterValue,6,*) 113 | } 114 | 115 | // Now check if we have a set 116 | set nextbit=$EXTRACT(filterValue) 117 | if nextbit="{" { 118 | // Take off { from the start and } from the end 119 | set filterValue=$EXTRACT(filterValue,2,*-1) 120 | 121 | // Parse the list of values the same way that Joe does 122 | Set valueCount=..%SplitList(filterValue,.tList) 123 | set FilterStateArray=valueCount 124 | for i=1:1:valueCount { 125 | set FilterStateArray(i)=tList(i) 126 | } 127 | 128 | } else { 129 | // List has only 1 item; put it into the array 130 | set FilterStateArray=1 131 | set FilterStateArray(1)=filterValue 132 | } 133 | 134 | quit $$$OK 135 | } 136 | 137 | /// Given a filter name and a FilterStateArray, 138 | /// returns a string that can be used as an MDX set. 139 | ClassMethod BuildString(filterName, ByRef FilterStateArray) As %String [ Private ] 140 | { 141 | if (FilterStateArray = 1) { 142 | set string=filterName_"."_FilterStateArray(1) 143 | if (FilterStateArray("not")=1) { 144 | set string=string_".%NOT" 145 | } 146 | } else { 147 | set string="%OR({" 148 | for i=1:1:FilterStateArray{ 149 | set string=string_filterName_"."_FilterStateArray(i)_"," 150 | } 151 | // Remove trailing comma and close set (which is wrapped in %OR) 152 | set string=$EXTRACT(string,1,*-1) 153 | set string=string_"})" 154 | 155 | // Deal with NOT case 156 | if FilterStateArray("not")=1 { 157 | set string="EXCEPT("_filterName_".MEMBERS,"_string_")" 158 | } 159 | } 160 | quit string 161 | } 162 | 163 | ClassMethod %OnGetFilterList(Output pFilters As %List, pDataSourceName As %String = "") As %Status 164 | { 165 | set tSC = ##class(%DeepSee.Dashboard.Utils).%GetFiltersForDataSource(..#CUBE_".cube",.tFilters) 166 | quit:$$$ISERR(tSC) 167 | 168 | set i = "" 169 | for { 170 | set i = $order(tFilters(i), 1, data) 171 | quit:i="" 172 | 173 | set pFilters($i(pFilters)) = $lb($lg(data,2), $lg(data,1),,1) 174 | } 175 | quit $$$OK 176 | } 177 | 178 | } 179 | 180 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientSet2.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class represents an additional set of patients collected 5 | /// by a separate research team and put into a separate table. It does 6 | /// not have all the properties that BI.Study.Patient has. 7 | /// For information on these properties and methods, see the corresponding 8 | /// comments in BI.Study.Patient. 9 | /// This table is populated only if you use the X option when running the 10 | /// GenerateData() method in BI.Populate. 11 | Class BI.Study.PatientSet2 Extends %Persistent 12 | { 13 | 14 | Property PatientID As %String; 15 | 16 | Property Gender As %String; 17 | 18 | Property Age As %Integer; 19 | 20 | Property PrimaryCarePhysician As BI.Study.Doctor; 21 | 22 | Property Allergies As list Of BI.Study.PatientAllergy; 23 | 24 | Property Diagnoses As list Of BI.Study.PatientDiagnosis; 25 | 26 | Property HomeCity As %String; 27 | 28 | Property PatientGroup As %String; 29 | 30 | Property TestScore As %Numeric; 31 | 32 | /// Called by BI.Populate:GenerateData(); see the comments for that method. 33 | ClassMethod GenerateData(patCount As %Integer = 500, options As %String = "ADT", genNulls As %Boolean = 1) As %Status 34 | { 35 | set status=$$$OK 36 | //first kill extent and kill extents of child tables 37 | //never use %KillExtent() in a real application 38 | do ..%KillExtent() 39 | set status=..AddPatients(patCount,options,genNulls) 40 | quit status 41 | } 42 | 43 | /// Called by BI.Populate:GenerateData(); see the comments for that method. 44 | /// Can also be called directly to add patients after the initial setup. 45 | ClassMethod AddPatients(patCount As %Integer = 500, options As %String = "AD", genNulls = 1) As %Status 46 | { 47 | set status=$$$OK 48 | 49 | // Check options; what do we need to generate? 50 | if ($FIND(options,"A")) {set generateallergies=1} 51 | else {set generateallergies=0} 52 | if ($FIND(options,"D")) {set generatediagnoses=1} 53 | else {set generatediagnoses=0} 54 | 55 | set dcount=##class(BI.Populate).Count("BI.Study.Diagnosis") 56 | set currentpatcount=##class(BI.Populate).Count($CLASSNAME()) 57 | if (currentpatcount=0) {set initPat=5000} 58 | else {set initPat=patCount+1} 59 | set idnumber=initPat 60 | 61 | for n = 1:1:patCount { 62 | set pat=##class(BI.Study.PatientSet2).%New() 63 | set idnumber=idnumber+1 ; increment without any gaps 64 | set patid="SET2_"_idnumber 65 | set pat.PatientID=patid 66 | 67 | // Get age+gender combination 68 | set agegender=##class(BI.Populate).RandomGenderAndAge() 69 | set pat.Gender=$Piece(agegender,",",1) 70 | set pat.Age=$Piece(agegender,",",2) 71 | 72 | // Assign a doctor 73 | set docid=##class(BI.Populate).GetRandomId("BI.Study.Doctor") 74 | set doctor=##class(BI.Study.Doctor).%OpenId(docid,0) 75 | set pat.PrimaryCarePhysician=doctor 76 | 77 | // Null out this property randomly to simulate missing data 78 | if genNulls &&##class(BI.Populate).RandomTrue(15){ 79 | set pat.PrimaryCarePhysician="" 80 | } 81 | 82 | // Assign to a patient group 83 | set grouplist=$LB("Group A","Group B") 84 | set groupID=$RANDOM($LISTLENGTH(grouplist))+1 85 | set pat.PatientGroup=$LI(grouplist,groupID) 86 | 87 | // Set TestScore property and assign a test version 88 | set pat.TestScore=50+$RANDOM(50) 89 | 90 | // Null out the previous two properties in some cases 91 | // score can be null but won't be 0 (see above) 92 | // this lets us see how measures treat null values 93 | if (genNulls && ##class(BI.Populate).RandomTrue(20)){ 94 | set pat.TestScore="" 95 | set pat.PatientGroup="" 96 | } 97 | 98 | // Select a city 99 | set cityid=##class(BI.Populate).GetRandomId("BI.Study.City") 100 | set city=##class(BI.Study.City).%OpenId(cityid,0) 101 | set pat.HomeCity=city.Name 102 | 103 | // If asked, generate some allergies 104 | if generateallergies { 105 | set status=##class(BI.Study.PatientAllergy).GenerateAllergies(pat,genNulls) 106 | if $$$ISERR(status) {do $System.Status.DisplayError(status) write !, "Allergies insert error"} 107 | } 108 | 109 | // If asked, generate some diagnoses 110 | if generatediagnoses { 111 | // Iterate through available diagnoses, look up chance of patient's 112 | // receiving this diagnosis, based on gender & age 113 | // save diagnosis data in all diagnosis properties 114 | set diagnosiscount=0 ; initialize this so we know if we're on the first one 115 | set diaglist="" 116 | for k=1:1:dcount{ 117 | set potentialdiagnosis=##class(BI.Study.Diagnosis).%OpenId(k,0) 118 | 119 | // Get the code 120 | set code=potentialdiagnosis.Code 121 | 122 | // Look up how likely this patient is to have this diagnosis 123 | set chance=##class(BI.Study.Diagnosis).GetPercentChance(code,pat.Gender,pat.Age) 124 | 125 | if ##class(BI.Populate).RandomTrue(chance) { 126 | set diagnosiscount=diagnosiscount+1 127 | set desc=potentialdiagnosis.Description 128 | set diagdocid=##class(BI.Populate).GetRandomId("BI.Study.Doctor") 129 | set diagdoc=##class(BI.Study.Doctor).%OpenId(diagdocid,0) 130 | 131 | // Populate Diagnoses property 132 | set patdiag=##class(BI.Study.PatientDiagnosis).%New() ; this object is serial 133 | set patdiag.DiagnosisCode=code 134 | set patdiag.DiagnosedBy=diagdoc 135 | set status=pat.Diagnoses.Insert(patdiag) 136 | if $$$ISERR(status) {do $System.Status.DisplayError(status) write !, "Diagnoses error"} 137 | } 138 | } 139 | 140 | } 141 | 142 | set status=pat.%Save() 143 | if $$$ISERR(status) {do $System.Status.DisplayError(status) write !, "Patient save error"} 144 | if ('(n#1000)) {write $C(13,27)_"[0J"_$FN(n,",",0)_" patients created in BI.Study.Patient"} 145 | 146 | 147 | // Create an "extent set" from which we can later get random IDs 148 | set status=##class(BI.Populate).UpdateIdCache($CLASSNAME()) 149 | 150 | write ! 151 | write $C(13,27)_"[0J"_$FN(+$G(n),",",0)_" patient(s) created in BI.Study.PatientSet2" 152 | quit status 153 | } 154 | } 155 | 156 | Storage Default 157 | { 158 | 159 | 160 | %%CLASSNAME 161 | 162 | 163 | PatientID 164 | 165 | 166 | Gender 167 | 168 | 169 | Age 170 | 171 | 172 | PrimaryCarePhysician 173 | 174 | 175 | Allergies 176 | 177 | 178 | Diagnoses 179 | 180 | 181 | HomeCity 182 | 183 | 184 | PatientGroup 185 | 186 | 187 | TestScore 188 | 189 | 190 | ^BI.Study.PatientSet2D 191 | PatientSet2DefaultData 192 | ^BI.Study.PatientSet2D 193 | ^BI.Study.PatientSet2I 194 | ^BI.Study.PatientSet2S 195 | %Storage.Persistent 196 | } 197 | 198 | } 199 | 200 | -------------------------------------------------------------------------------- /src/cls/BI/Study/PatientEncounter.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// A patient can have multiple encounters 5 | /// (interactions with a medical professional). The encounter data here is minimal, but you 6 | /// can create dimensions/levels based on the number of encounters a patient has, as well as 7 | /// on the attending physician for those encounters. 8 | /// This table is populated only if you use the E option when running the GenerateData() 9 | /// method in BI.Populate. You can also use the AddEncounters() method 10 | /// of this class to add encounters to existing patients. 11 | Class BI.Study.PatientEncounter Extends %Persistent 12 | { 13 | 14 | Property Patient As BI.Study.Patient; 15 | 16 | Property EncounterNumber As %String; 17 | 18 | Property PrimaryDoctor As BI.Study.Doctor; 19 | 20 | Property EncounterType As %String; 21 | 22 | /// Called by BI.Study.Patient:AddPatients(). 23 | ClassMethod CreateEncounters(pat As BI.Study.Patient) As %Status 24 | { 25 | 26 | set encNo=100 ; starting value 27 | 28 | set encountercount=..GetRandomEncounterCount(pat.Age) 29 | 30 | set patnumber=$PIECE(pat.PatientID,"_",2) ; get number part from this string 31 | for i=1:1:encountercount { 32 | set encounter=##class(BI.Study.PatientEncounter).%New() 33 | set encounter.Patient=pat 34 | set encounter.EncounterNumber=patnumber_"-"_encNo 35 | 36 | set docid=##class(BI.Populate).GetRandomId("BI.Study.Doctor") 37 | set encounter.PrimaryDoctor=##class(BI.Study.Doctor).%OpenId(docid,0) 38 | set encounter.EncounterType=..GetRandomEncounterType() 39 | 40 | set status=encounter.%Save() 41 | set encNo=encNo+1 42 | } 43 | quit status 44 | } 45 | 46 | /// Iterate through patients and add encounters randomly to some percentage. 47 | /// if rebuild is 1, this method updates the BI indices for each patient 48 | /// affectedby these changes. 49 | ClassMethod AddEncounters(percent As %Numeric = 20, rebuild As %Boolean = 1) As %Status 50 | { 51 | set ^BI.Study.Log($I(^BI.Study.Log))=$zdatetime($h,2,3)_" Adding encounters..." 52 | 53 | // Create or update the "ID extent sets" from which we can later get random IDs 54 | set status=##class(BI.Populate).UpdateIdCache("BI.Study.Patient") 55 | set status=##class(BI.Populate).UpdateIdCache("BI.Study.Doctor") 56 | 57 | set patcount=##class(BI.Populate).Count("BI.Study.Patient") 58 | set changecount=0 59 | 60 | // First check to see if we have any encounter data; if we don't, we can add 61 | // encounters more quickly 62 | set myquery="SELECT Count(*) as ENCCOUNT FROM BI_Study.PatientEncounter" 63 | set rset=##class(%ResultSet).%New("%DynamicQuery:SQL") 64 | set status=rset.Prepare(myquery) 65 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit} 66 | set status=rset.Execute() 67 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit} 68 | set enccount=0 69 | while rset.Next() { 70 | set enccount=rset.Data("ENCCOUNT") 71 | } 72 | 73 | // Roll the dice as many times as we have patients; this is not the same 74 | // as iterating through the patients but does provide similar coverage 75 | for i=1:1:patcount 76 | { 77 | if ##class(BI.Populate).RandomTrue(percent) 78 | { 79 | set changecount=changecount+1 80 | set id=##class(BI.Populate).GetRandomId("BI.Study.Patient") 81 | set pat=##class(BI.Study.Patient).%OpenId(id,0) 82 | set patID=pat.%Id() ; use when querying extent 83 | 84 | // If we already have encounter data, we must 85 | // get highest number encounter for this patient, if any 86 | if (enccount>0) { 87 | set myquery="SELECT EncounterNumber FROM BI_Study.PatientEncounter WHERE Patient=? ORDER BY EncounterNumber" 88 | set rset=##class(%ResultSet).%New("%DynamicQuery:SQL") 89 | set status=rset.Prepare(myquery) 90 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit} 91 | set status=rset.Execute(patID) 92 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit} 93 | set result="" 94 | while rset.Next() { 95 | set result=rset.Data("EncounterNumber") 96 | } 97 | if (result'="") { 98 | set highestencno=result 99 | set encNo=$PIECE(highestencno,"-",2) + 1 ; increment by 1 from what's there 100 | } else { 101 | // This patient has no encounters yet 102 | set encNo=100 103 | } 104 | } else { 105 | set encNo=100 106 | } 107 | 108 | // Number of encounters to add 109 | set encountercount=$RANDOM(2)+1 ; ADD 1 or 2 encounters 110 | 111 | // Base part for encounter number 112 | set patnumber=$PIECE(pat.PatientID,"_",2) ; get number part from this string 113 | 114 | for j=1:1:encountercount { 115 | set encounter=##class(BI.Study.PatientEncounter).%New() 116 | set encounter.Patient=pat 117 | set encounter.EncounterNumber=patnumber_"-"_encNo 118 | set docid=##class(BI.Populate).GetRandomId("BI.Study.Doctor") 119 | set encounter.PrimaryDoctor=##class(BI.Study.Doctor).%OpenId(docid,0) 120 | set encounter.EncounterType=..GetRandomEncounterType() 121 | 122 | set status=encounter.%Save() 123 | set encNo=encNo+1 124 | } 125 | 126 | if rebuild { 127 | // Because the BI.Study.Patient table is unaware of the BI.Study.PatientEncounter 128 | // table, changing info in BI.Study.PatientEncounter does NOT fire any triggers for 129 | // the patients, so it is necessary to update the indices for those patients 130 | set id=pat.%Id() 131 | 132 | Do ##class(%DeepSee.Utils).%ProcessFact("patients",id) 133 | } 134 | } 135 | } 136 | set ^BI.Study.Log($I(^BI.Study.Log))=$zdatetime($h,2,3)_" Added encounters for "_changecount_" patients" 137 | // If rebuild {Kill %this} ; needed because zzBuildOne doesn't clean this up 138 | quit $$$OK 139 | } 140 | 141 | /// Clear out records in PatientEncounter; called when you delete patients. 142 | ClassMethod DeleteEncounters(pat As BI.Study.Patient) As %Status 143 | { 144 | set patid=pat.%Id() 145 | set myquery="DELETE FROM BI_Study.PatientEncounter WHERE Patient=?" 146 | set rset=##class(%ResultSet).%New("%DynamicQuery:SQL") 147 | set status=rset.Prepare(myquery) 148 | if $$$ISERR(status) {Do $System.Status.DisplayError(status) Quit} 149 | set status=rset.Execute(patid) 150 | quit status 151 | } 152 | 153 | ClassMethod GetRandomEncounterType() As %String 154 | { 155 | if ##class(BI.Populate).RandomTrue(5) { 156 | quit "Emergency" 157 | } elseif ##class(BI.Populate).RandomTrue(30) { 158 | quit "Outpatient" 159 | } else { 160 | quit "Inpatient" 161 | } 162 | } 163 | 164 | ClassMethod GetRandomEncounterCount(age As %Numeric) As %Integer 165 | { 166 | set factor=(age+1)*1.5 167 | set count=3 + $RANDOM(20) + $RANDOM(factor) 168 | quit count 169 | } 170 | 171 | Index PatientIndex On Patient; 172 | 173 | Storage Default 174 | { 175 | 176 | 177 | %%CLASSNAME 178 | 179 | 180 | Patient 181 | 182 | 183 | EncounterNumber 184 | 185 | 186 | PrimaryDoctor 187 | 188 | 189 | EncounterType 190 | 191 | 192 | ^BI.Study.PatientEncounterD 193 | PatientEncounterDefaultData 194 | ^BI.Study.PatientEncounterD 195 | ^BI.Study.PatientEncounterI 196 | ^BI.Study.PatientEncounterS 197 | %Storage.Persistent 198 | } 199 | 200 | } 201 | 202 | -------------------------------------------------------------------------------- /src/cls/HoleFoods/Cube.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This is a sample DeepSee data model.
3 | /// This cube represents a model for the fictional "HoleFoods" corporation. 4 | /// It is based on the classes within the HoleFoods package.
5 | /// To create data for this model, the easiest thing to do is to 6 | /// use the BuildData method within the HoleFoods.Utils class:
7 | /// From the command line:
8 | /// 9 | /// Do ##class(HoleFoods.Utils).BuildData(1000000,1,1) 10 | /// 11 | /// The first argument is the number of records to create, 12 | /// the second argument indicates that index building should be done in parallel, 13 | /// the third is a verbose flag; if true, then progress is displayed as the data is built. 14 | Class HoleFoods.Cube Extends %DeepSee.CubeDefinition [ DependsOn = (HoleFoods.Transaction, HoleFoods.KPIAction) ] 15 | { 16 | 17 | Parameter DOMAIN = "HOLEFOODS"; 18 | 19 | /// This xml document defines the HoleFoods model. 20 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 21 | { 22 | 29 | 30 | 32 | 33 | 36 | 37 | 40 | 41 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 88 | 91 | 94 | 95 | 100 | 101 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | } 173 | 174 | } 175 | 176 | -------------------------------------------------------------------------------- /src/cls/BI/Study/Doctor.cls: -------------------------------------------------------------------------------- 1 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 2 | /// This class is part of the BI Patients sample, whose purpose is to provide 3 | /// sample data for use with InterSystems IRIS BI. 4 | /// This class contains the doctors. 5 | Class BI.Study.Doctor Extends %Persistent 6 | { 7 | 8 | Property FirstName As %String(MAXLEN = 100); 9 | 10 | Property LastName As %String(MAXLEN = 100); 11 | 12 | /// City where this doctor primarily works; 13 | Property MainCity As BI.Study.City; 14 | 15 | /// Group into which this "study" places this doctor 16 | Property DoctorGroup As %String; 17 | 18 | /// Primary focus of this doctor's work; 19 | Property DoctorType As %String; 20 | 21 | /// Average number of patients that this doctor sees per week 22 | /// (included to provide a numeric value in this table) 23 | Property PatientsPerWeek As %Numeric; 24 | 25 | /// This method reads the XData block in this class and uses it to populate the table. 26 | /// This method is called by BI.Populate:GenerateData(). 27 | ClassMethod GenerateData(count As %Integer = 100, genNulls = 1) As %Status 28 | { 29 | set status=$$$OK 30 | //first kill extent 31 | //never use %KillExtent() in a real application 32 | do ..%KillExtent() 33 | set ^BI.Study.SetupData("Pediatricians")="" 34 | set ^BI.Study.SetupData("OBGYNs")="" 35 | set ^BI.Study.SetupData("OtherDoctors")="" 36 | 37 | 38 | For n = 1:1:count { 39 | set doc = ##class(BI.Study.Doctor).%New() 40 | set doc.FirstName = ##class(%PopulateUtils).FirstName() 41 | set doc.LastName = ##class(%PopulateUtils).LastName() 42 | 43 | // Assign to a doctor group 44 | set grouplist=$LB("I","II","III") 45 | set groupID=$RANDOM($LISTLENGTH(grouplist))+1 46 | set doc.DoctorGroup=$LI(grouplist,groupID) 47 | 48 | // Set PatientsPerWeek property 49 | set doc.PatientsPerWeek=130+$RANDOM(40) 50 | 51 | // Null out the previous two properties in some cases 52 | if (genNulls && ##class(BI.Populate).RandomTrue(20)){ 53 | set doc.PatientsPerWeek="" 54 | set doc.DoctorGroup="" 55 | } 56 | 57 | 58 | // Select a city 59 | set cityid=##class(BI.Populate).GetRandomId("BI.Study.City") 60 | set doc.MainCity=##class(BI.Study.City).%OpenId(cityid,0) 61 | 62 | // Specify the doctor type; these are assigned somewhat randomly 63 | if ##class(BI.Populate).RandomTrue(70) { 64 | set typelist=$LB("General Physician","Internist","Pediatrician","OB/GYN") 65 | set typeid=$RANDOM($LISTLENGTH(typelist))+1 66 | set doc.DoctorType=$LI(typelist,typeid) 67 | } 68 | else { 69 | set typelist=$LB("Anesthesiologist","Allergist","Cardiologist","Dermatologist", 70 | "Emergency Physician","Gastroenterologist","Radiologist","Surgeon") 71 | set typeid=$RANDOM($LISTLENGTH(typelist))+1 72 | set doc.DoctorType=$LI(typelist,typeid) 73 | } 74 | if (doc.DoctorType="Pediatrician") { 75 | set ^BI.Study.SetupData("Pediatricians")=^BI.Study.SetupData("Pediatricians")_","_n 76 | } elseif (doc.DoctorType="OB/GYN") { 77 | set ^BI.Study.SetupData("OBGYNs")=^BI.Study.SetupData("OBGYNs")_","_n 78 | } else { 79 | set ^BI.Study.SetupData("OtherDoctors")=^BI.Study.SetupData("OtherDoctors")_","_n 80 | } 81 | 82 | set status=doc.%Save() 83 | if $$$ISERR(status) {do $System.Status.DisplayError(status)} 84 | 85 | } 86 | set ^BI.Study.SetupData("Pediatricians")=$ZSTRIP(^BI.Study.SetupData("Pediatricians"),"<",",") 87 | set ^BI.Study.SetupData("OBGYNs")=$ZSTRIP(^BI.Study.SetupData("OBGYNs"),"<",",") 88 | 89 | // Create an "extent set" from which we can later get random IDs 90 | set status=##class(BI.Populate).UpdateIdCache($CLASSNAME()) 91 | quit status 92 | } 93 | 94 | /// Randomly change doctor group and patients per week for some doctors. 95 | /// if rebuild is 1, this method updates the BI indices for each patient affected 96 | /// by these changes. 97 | ClassMethod ChangeSomeDoctors(percent As %Numeric = 20, rebuild As %Boolean = 1) 98 | { 99 | set ^BI.Study.Log($I(^BI.Study.Log))=$zdatetime($h,2,3)_" Changing some doctor data..." 100 | 101 | // Create an "extent set" from which we can later get random IDs 102 | set status=##class(BI.Populate).UpdateIdCache($CLASSNAME()) 103 | 104 | set changecount=0 105 | set listLength=##class(BI.Populate).Count($CLASSNAME()) 106 | 107 | // Throw the dice once as many times as we have doctors; not the same as 108 | // looping through doctors but close in overall effect 109 | for i=1:1:listLength { 110 | if ##class(BI.Populate).RandomTrue(percent) 111 | { 112 | set docid=##class(BI.Populate).GetRandomId($CLASSNAME()) 113 | set doc=..%OpenId(docid) 114 | 115 | // Assign to a doctor group 116 | set grouplist=$LB("I","II","III") 117 | set groupID=$RANDOM($LISTLENGTH(grouplist))+1 118 | set doc.DoctorGroup=$LI(grouplist,groupID) 119 | 120 | // Set PatientsPerWeek property 121 | set doc.PatientsPerWeek=130+$RANDOM(40) 122 | do doc.%Save() 123 | 124 | if rebuild { 125 | // Because doctors are in a separate table, changing info for a 126 | // doctor does NOT fire any triggers for the patients, 127 | // so it is necessary to figure out which patients are affected 128 | // and update the indices for those patients 129 | 130 | set myquery="SELECT ID FROM BI_Study.Patient WHERE PrimaryCarePhysician=?" 131 | set rset=##class(%ResultSet).%New("%DynamicQuery:SQL") 132 | set status=rset.Prepare(myquery) 133 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 134 | set status=rset.Execute(docid) 135 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 136 | while rset.Next() { 137 | set patid=rset.Data("ID") 138 | 139 | do ##class(%DeepSee.Utils).%ProcessFact("patients",patid) 140 | 141 | } 142 | } 143 | set changecount=changecount+1 144 | } 145 | } 146 | 147 | // If rebuild {Kill %this} ; needed because zzBuildone doesn't clean this up 148 | set ^BI.Study.Log($I(^BI.Study.Log))=$zdatetime($h,2,3)_" "_changecount_" doctors changed" 149 | } 150 | 151 | /// Based on patient age (in years) and gender ("F" or "M"), return the ID of a suitable doctor 152 | ClassMethod GetDoctorId(patientAge As %Integer = "", patientGender As %String = "") As %Integer 153 | { 154 | if (patientAge="") { 155 | quit ..GetRandomOtherDoctor() 156 | } elseif (patientAge<12) { 157 | if ##class(BI.Populate).RandomTrue(90) { 158 | quit ..GetRandomPediatrician() 159 | } else { 160 | quit ..GetRandomOtherDoctor() 161 | } 162 | } 163 | 164 | if (patientGender="") { 165 | quit ..GetRandomOtherDoctor() 166 | } elseif (patientGender="F") { 167 | if ##class(BI.Populate).RandomTrue(70) { 168 | quit ..GetRandomOBGYN() 169 | } else { 170 | quit ..GetRandomOtherDoctor() 171 | } 172 | } else { 173 | quit ..GetRandomOtherDoctor() 174 | } 175 | } 176 | 177 | ClassMethod GetRandomPediatrician() As %Integer 178 | { 179 | set choosefrom=^BI.Study.SetupData("Pediatricians") 180 | set choosenumber=$L(choosefrom,",") 181 | set randomnumber=$RANDOM(choosenumber)+1 182 | set randomdoc=$P(choosefrom,",",randomnumber) 183 | quit randomdoc 184 | } 185 | 186 | ClassMethod GetRandomOBGYN() 187 | { 188 | set choosefrom=^BI.Study.SetupData("OBGYNs") 189 | set choosenumber=$L(choosefrom,",") 190 | set randomnumber=$RANDOM(choosenumber)+1 191 | set randomdoc=$P(choosefrom,",",randomnumber) 192 | quit randomdoc 193 | } 194 | 195 | ClassMethod GetRandomOtherDoctor() 196 | { 197 | set choosefrom=^BI.Study.SetupData("OtherDoctors") 198 | set choosenumber=$L(choosefrom,",") 199 | set randomnumber=$RANDOM(choosenumber)+1 200 | set randomdoc=$P(choosefrom,",",randomnumber) 201 | quit randomdoc 202 | } 203 | 204 | Storage Default 205 | { 206 | 207 | 208 | %%CLASSNAME 209 | 210 | 211 | FirstName 212 | 213 | 214 | LastName 215 | 216 | 217 | MainCity 218 | 219 | 220 | DoctorGroup 221 | 222 | 223 | DoctorType 224 | 225 | 226 | PatientsPerWeek 227 | 228 | 229 | ^BI.Study.DoctorD 230 | DoctorDefaultData 231 | ^BI.Study.DoctorD 232 | ^BI.Study.DoctorI 233 | ^BI.Study.DoctorS 234 | %Storage.Persistent 235 | } 236 | 237 | } 238 | 239 | -------------------------------------------------------------------------------- /src/cls/BI/APISamples.cls: -------------------------------------------------------------------------------- 1 | Include %occInclude 2 | 3 | /// Use or operation of this code is subject to acceptance of the license available in the code repository for this code. 4 | Class BI.APISamples 5 | { 6 | 7 | /// Executes a hardcoded query and prints the results. 8 | /// Returns the result set as output. 9 | ClassMethod RunQuery1(Output result As %DeepSee.ResultSet) As %Status 10 | { 11 | set rset=##class(%DeepSee.ResultSet).%New() 12 | set query="SELECT MEASURES.[%COUNT] ON 0, diagd.MEMBERS ON 1 FROM patients" 13 | set status=rset.%PrepareMDX(query) 14 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 15 | 16 | set status=rset.%Execute() 17 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 18 | 19 | write !, "Full results are as follows ***************",! 20 | do rset.%Print() 21 | quit $$$OK 22 | } 23 | 24 | /// Executes a query that uses a named parameter and prints the results. 25 | /// Returns the result set as output. 26 | ClassMethod RunQuery2(city As %String = "Magnolia", Output result As %DeepSee.ResultSet) As %Status 27 | { 28 | set rset=##class(%DeepSee.ResultSet).%New() 29 | set query="WITH %PARM c AS 'value:Magnolia'" 30 | _"SELECT homed.[city].@c ON 0 FROM patients" 31 | set status=rset.%PrepareMDX(query) 32 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 33 | 34 | set myparms("c")=city 35 | set status=rset.%Execute(.myparms) 36 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 37 | 38 | write !, "Full results are as follows ***************",! 39 | do rset.%Print() 40 | quit $$$OK 41 | } 42 | 43 | /// Executes a query that does a detail listing and prints the results. 44 | /// Returns the result set as output. 45 | ClassMethod RunQuery3() 46 | { 47 | set rset=##class(%DeepSee.ResultSet).%New() 48 | 49 | set query="DRILLTHROUGH SELECT gend.female ON 0,birthd.[1913] ON 1 " 50 | _"FROM patients RETURN PatientID,PrimaryCarePhysician->LastName" 51 | 52 | set status=rset.%PrepareMDX(query) 53 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 54 | 55 | set status=rset.%Execute() 56 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit} 57 | 58 | write !, "Listing details for the first cell are as follows ***************",! 59 | do rset.%PrintListing() 60 | } 61 | 62 | /// Executes a query and prints the results. 63 | /// Then for comparison, displays a specific cell. 64 | ClassMethod ShowCell() As %Status 65 | { 66 | set rset=##class(%DeepSee.ResultSet).%New() 67 | set query="SELECT MEASURES.[avg age] ON 0, homed.[city].MEMBERS ON 1 " 68 | _"FROM patients" 69 | set status=rset.%PrepareMDX(query) 70 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 71 | 72 | set status=rset.%Execute() 73 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 74 | 75 | write !, "Full results are as follows ***************",! 76 | do rset.%Print() 77 | 78 | write !, "Cell 1,5 is as follows ***************",! 79 | write rset.%GetOrdinalValue(1,5) 80 | quit status 81 | } 82 | 83 | /// Executes a query and prints the results. 84 | /// Then for comparison, displays information about the row labels. 85 | ClassMethod ShowRowLabels() As %Status 86 | { 87 | set rset=##class(%DeepSee.ResultSet).%New() 88 | set query="SELECT CROSSJOIN(aged.[age group].MEMBERS," 89 | _"gend.gender.MEMBERS) ON 1 FROM patients" 90 | set status=rset.%PrepareMDX(query) 91 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 92 | 93 | set status=rset.%Execute() 94 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 95 | 96 | write !, "Full results are as follows ***************",! 97 | do rset.%Print() 98 | 99 | write !, "Labels used on the rows are as follows ***************",! 100 | for j=1:1:rset.%GetRowCount() { 101 | write !, "Row ",j 102 | set labelcount=rset.%GetOrdinalLabel(.pLabel,2,j) 103 | For i=1:1:labelcount { 104 | write !, " label("_i_") is "_pLabel(i) 105 | } 106 | } 107 | 108 | quit $$$OK 109 | } 110 | 111 | /// Given a result set as input, this method generates a report on 112 | /// the query metadata. 113 | ClassMethod ShowQueryMetadata(rset As %DeepSee.ResultSet) As %Status 114 | { 115 | set cubename=rset.%GetCubeName() 116 | write !, "This result set comes from the following cube: ",cubename,! 117 | 118 | set status=rset.%GetParameterInfo(.pParms) 119 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 120 | if $DATA(pParms) { 121 | write "The query uses the following parameters:",! 122 | set p = $ORDER(pParms("")) 123 | While (p '= "") { 124 | write $$$UPPER(p), " = " ,$GET(pParms(p,"VALUE")),! 125 | set p = $ORDER(pParms(p)) 126 | } 127 | } 128 | set query=rset.%GetQueryText() 129 | write "The query is as follows:",!, query,! 130 | 131 | set isdrill=rset.%IsDrillThrough() 132 | if isdrill { 133 | set listingsql=rset.%GetListingSQL() 134 | write !!, "It uses the following SQL to drill into the source table:" 135 | write !, listingsql 136 | } 137 | } 138 | 139 | /// Given a result set as input, this method generates a report on 140 | /// the result metadata. 141 | ClassMethod ShowResultMetadata(rset As %DeepSee.ResultSet) 142 | { 143 | set cubename=rset.%GetCubeName() 144 | write !, "This result set comes from the cube ",cubename 145 | 146 | set querykey=rset.%GetQueryKey() 147 | set cellcount=##class(%DeepSee.ResultSet).%GetCellCount(cubename,querykey) 148 | write !, "It has ", cellcount, " cells" 149 | 150 | //For i=1:1:cellcount{ 151 | // write !, "cell number ",i," has the value ",rset.%GetOrdinalValue(i) 152 | //} 153 | } 154 | 155 | /// Given a result set as input, this method generates a report on 156 | /// the slicer statement for a given cell range. 157 | ClassMethod ShowSlicerStatement(rset As %DeepSee.ResultSet, Row1 As %Integer = 1, Col1 As %Integer = 1, Row2 As %Integer, Col2 As %Integer) As %Status 158 | { 159 | if '$DATA(Row2) {set Row2=Row1} 160 | if '$DATA(Col2) {set Col2=Col1} 161 | 162 | set status=rset.%GetSlicerForCellRange(.slicer,Row1,Col1,Row2,Col2) 163 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit status} 164 | 165 | write !, "The requested cell range:" 166 | write !, " Columns ",Col1, " through ", Col2 167 | write !, " Rows ",Row1, " through ", Row2 168 | 169 | write !, "The slicer statement for the given cell range is as follows:" 170 | write !, slicer 171 | 172 | if 'rset.%IsDrillThrough(){ 173 | write !!, "For comparison, the query results are as follows:",! 174 | do rset.%Print() 175 | } 176 | Else { 177 | write !!, "This is a drillthrough query and %Print " 178 | _"does not provide a useful basis of comparison" 179 | } 180 | } 181 | 182 | /// Executes a hardcoded query and returns a result set. 183 | ClassMethod GetResultSet1() As %DeepSee.ResultSet 184 | { 185 | set rset=##class(%DeepSee.ResultSet).%New() 186 | set query="SELECT {MEASURES.[avg test score],MEASURES.[%COUNT]} ON 0, " 187 | _"diagd.h1.diagnoses.MEMBERS ON 1 FROM patients" 188 | set status=rset.%PrepareMDX(query) 189 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 190 | 191 | set status=rset.%Execute() 192 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 193 | 194 | quit rset 195 | } 196 | 197 | /// Executes a hardcoded query and returns a result set. 198 | ClassMethod GetResultSet2(city As %String = "Magnolia") As %DeepSee.ResultSet 199 | { 200 | set rset=##class(%DeepSee.ResultSet).%New() 201 | set query="WITH %PARM c AS 'value:Magnolia'" 202 | _"SELECT homed.h1.[city].@c ON 0 FROM patients" 203 | 204 | set status=rset.%PrepareMDX(query) 205 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 206 | 207 | set myparms("c")=city 208 | set status=rset.%Execute(.myparms) 209 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 210 | 211 | quit rset 212 | } 213 | 214 | /// executes a hardcoded query and returns a result set 215 | ClassMethod GetResultSet3() As %DeepSee.ResultSet 216 | { 217 | set rset=##class(%DeepSee.ResultSet).%New() 218 | set query="DRILLTHROUGH SELECT gend.h1.gender.female ON 0,birthd.h1.year.[1913] ON 1 " 219 | _"FROM patients RETURN PatientID,PrimaryCarePhysician->LastName" 220 | 221 | set status=rset.%PrepareMDX(query) 222 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 223 | 224 | set status=rset.%Execute() 225 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 226 | 227 | quit rset 228 | } 229 | 230 | /// Executes a hardcoded query and returns a result set. 231 | ClassMethod GetResultSet4() As %DeepSee.ResultSet 232 | { 233 | set rset=##class(%DeepSee.ResultSet).%New() 234 | set query="SELECT CROSSJOIN(gend.h1.gender.MEMBERS,MEASURES.[%COUNT]) ON 0, " 235 | _"aged.h1.[age bucket].MEMBERS ON 1 FROM patients" 236 | set status=rset.%PrepareMDX(query) 237 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 238 | 239 | set status=rset.%Execute() 240 | if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF} 241 | 242 | quit rset 243 | } 244 | 245 | } 246 | 247 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Samples-BI 2 | This is the README file for SAMPLES-BI. 3 | The end of the file has setup instructions. 4 | 5 | - [Samples-BI](#samples-bi) 6 | - [Overview](#overview) 7 | - [Contents of the BI package](#contents-of-the-bi-package) 8 | - [Contents of the HoleFoods package](#contents-of-the-holefoods-package) 9 | - [Setup instructions](#setup-instructions) 10 | - [Setup with ZPM](#setup-with-zpm) 11 | - [Step-by-step Installation](#step-by-step-installation) 12 | 13 | --- 14 | Use or operation of this code is subject to acceptance of the license available in the code 15 | repository for this code. 16 | 17 | --- 18 | 19 | ## Overview 20 | 21 | Samples-BI is meant for use with the InterSystems IRIS Business Intelligence capabilities. 22 | In order to use this sample, you must have an InterSystems IRIS license that includes these capabilities. 23 | 24 | These classes provide sample data that you can use to explore the capabilities of InterSystems IRIS BI. 25 | They also demonstrate ways to create BI models using InterSystems IRIS BI. 26 | 27 | This sample contains two packages: 28 | * The `BI` package, which provides simple data representing a fictitious medical study, and also provides 29 | an InterSystems IRIS BI model that uses that data. See details below. 30 | * The `HoleFoods` package, which provides simple data representing sales of food products, and also provides 31 | an InterSystems IRIS BI model that uses that data. See details below. 32 | 33 | The documentation for InterSystems IRIS Business Intelligence refers extensively to these samples. 34 | The HoleFoods model provides a quick and easy introduction to BI, and the BI model demonstrates 35 | null handling, list-based levels, and other features not included in HoleFoods. The BI package also 36 | explicitly demonstrates how to address more difficult modeling scenarios. 37 | 38 | After setup: 39 | * You can use the Analyzer to explore these BI models; for information, go [here](http://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=D2ANLY_ch_intro) 40 | * You can open the InterSystems IRIS dashboard and explore the sample dashboards and pivot 41 | tables. For information, see [this](http://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=D2DASH) 42 | * You can work through the steps of creating a BI model, pivot tables, and dashboards. 43 | See [this](http://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=D2DT_ch_setup) 44 | 45 | The repository also includes a number of configuration files and scripts that are not part of the sample itself. 46 | Please refer to [dev.md] for more about the role of these files. 47 | 48 | ### Contents of the BI package 49 | 50 | This package provides simple data representing a fictitious medical study, and also provides 51 | an InterSystems IRIS BI model that uses that data. 52 | 53 | * `BI.Model` package contains the classes that demonstrate BI model capability. 54 | - `BI.Model.PatientsCube` is the primary model; this defines the PATIENTS cube that is 55 | used in the MDX reference documentation and for most of the sample queries in the documentation. 56 | Other classes in BI.Model demonstrate special cases of various kinds; see the BI modeling guides. 57 | - `BI.Model.CompoundCube` package contains multiple cube definitions that collectively 58 | demonstrate how to create a compound cube. The Advanced Modeling guide discusses these cubes. 59 | - `BI.Model.KPIs` package contains sample InterSystems IRIS BI KPIs (key performance indicators). 60 | All of these KPIs are either discussed in the modeling guides or are used in the sample dashboards, 61 | to demonstrate different kinds of widgets. 62 | - `BI.Model.Portlet` package demonstrates a sample custom portlet. For details, see the 63 | Advanced Modeling guide. 64 | - `BI.Model.RelCube` package contains multiple cube definitions that collectively 65 | demonstrate how to create a set of related cubes. For details, see the Advanced Modeling guide. 66 | - `BI.Model.SubjectAreas` package contains multiple class definitions that that define 67 | subject areas, which are filtered cube definitions. The documentation refers to these in several 68 | places. The subject area DEMOMDX (`DeepSee.Model.DemoMDX`) is meant for use in getting familiar 69 | with MDX. 70 | 71 | * `BI.Study` package contains the classes that generate the data used by these models. The most 72 | important classes are these: 73 | - `BI.Study.Patient` is the central class and provides the source table for the PATIENTS cube. 74 | The patients are generated in an age-sex distribution that follows the 2010 US Census data. 75 | - `BI.Diagnosis` generates the diagnosis data used when generating patients. This diagnosis 76 | data consists of a small set of diagnoses for chronic conditions, along with morbidity data 77 | for these conditions (that is, chance of having this condition, based on age & sex). When data 78 | for a patient is generated, the patient is assigned zero or more diagnoses, based on the 79 | patient's age and sex, using this data. 80 | - `BI.Allergen` generates a common set of allergens, and BI.AllergySeverity generates a 81 | common set of allergy severities. When data for a patient is generated, the patient is assigned 82 | zero or more allergies, each to an allergen, with a specific severity. This enables BI modelers to 83 | explore multiple list-based levels and see how they relate to each other. 84 | - `BI.Study.Profession` generates a set of professions, to which the working-age patients are 85 | assigned. 86 | 87 | * `BI.Utils.MDXAutoFiltersKPI` is a sample class that adds cube-based filters to a KPI, when used 88 | as a superclass for that KPI. This class is discussed in the advanced modeling guide. 89 | 90 | * `BI.APISamples` demonstrates how to execute BI queries programmatically on the server. For details, 91 | see the BI implementation guide. 92 | 93 | * `BI.DashboardsEtc` contains the pivot table and dashboard definitions based on the models in 94 | the BI.Model package. 95 | 96 | * `BI.Populate` contains the wrapper code used to generate the data for this part of the BI sample. 97 | 98 | ### Contents of the HoleFoods package 99 | 100 | This package provides simple data representing sales of food products, and also provides 101 | an InterSystems IRIS BI model that uses that data. 102 | * `HoleFoods.Transaction`, `HoleFoods.Country`, `HoleFoods.Outlet`, `HoleFoods.Product`, and `HoleFoods.Region` 103 | generate the data. `HoleFoods.Transation` provides the source table used by the cube definitions 104 | for this part of the sample. 105 | * `HoleFoods.Cube` defines the HOLEFOODS cube, which is meant as a quick and easy introduction to BI 106 | in InterSystems IRIS. The documentation refers to this cube in numerous places. 107 | * `HoleFoods.BudgetCube` and `HoleFoods.CombinedCube` demonstrate a compound cube. 108 | * `HoleFoods.KPI*` classes define sample InterSystems IRIS BI KPIs (key performance indicators). 109 | For details, see the advanced modeling guide. 110 | * `HoleFoods.SampleListingGroup` is a sample listing group class. Via listing groups, you can define 111 | detail listings without modifying the cube definition. For details, see the modeling guides. 112 | * `HoleFoods.SubjectAreaAsia` is a sample subject area. For details, see the modeling guides. 113 | * `HoleFoods.Utils` contains the code used to generate data for the HoleFoods part of the BI sample. 114 | It also contains methods you can use to add or delete data, thus exercising techniques for 115 | keeping the cube contents synchronized with the source data. 116 | 117 | ## Setup instructions 118 | 119 | ### Setup with ZPM 120 | 121 | ZPM stands for ObjectScript Package Manager. It provides a simple and unified way to install ObjectScript modules [Learn More](https://community.intersystems.com/post/introducing-intersystems-objectscript-package-manager). You can either install ZPM on an existing InterSystems IRIS instance based on [these instructions](https://github.com/intersystems-community/zpm), or use one of the prebuilt Community Edition Docker images that have it pre-installed. The instructions below are for the latter option. If you already have ZPM installed, you can immediately proceed to jump to step 4. 122 | 123 | 0. Make sure you have [Docker-desktop](https://www.docker.com/products/docker-desktop) installed. 124 | 125 | 1. Pull the latest IRIS Community Edition image with zpm: 126 | ```Shell 127 | $ docker pull intersystemsdc/iris-community:latest 128 | ``` 129 | You can take the latest tag of IRIS or IRIS for Health Community Edition with ZPM [here](https://hub.docker.com/r/intersystemsdc/iris-community) 130 | 131 | 2. Run IRIS container with ZPM: 132 | ```Shell 133 | $ docker run --name irisce -d --publish 52773:52773 intersystemsdc/iris-community:latest 134 | ``` 135 | 3. RUN IRIS terminal 136 | ```Shell 137 | docker exec -it irisce iris session iris 138 | Node: c6e0f00b8d42, Instance: IRIS 139 | 140 | USER> 141 | ``` 142 | 143 | 4. From the IRIS terminal, start ZPM and install Samples-BI: 144 | ``` 145 | USER>zpm 146 | zpm: USER>install samples-bi 147 | 148 | [samples-bi] Reload START 149 | [samples-bi] Reload SUCCESS 150 | [samples-bi] Module object refreshed. 151 | [samples-bi] Validate START 152 | [samples-bi] Validate SUCCESS 153 | [samples-bi] Compile START 154 | [samples-bi] Compile SUCCESS 155 | [samples-bi] Activate START 156 | 2,187 row(s) created 157 | Building cube [HOLEFOODS] 158 | ... 159 | Complete 160 | Elapsed time: 0.009120s 161 | Source expression time: 0.000307s 162 | Defining term list Patients Pivots... 163 | Defining term list Patients RowSpecs... 164 | Defining YEAR pivot variable in PATIENTS cube 165 | 166 | [samples-bi] Configure SUCCESS 167 | [samples-bi] Activate SUCCESS 168 | ``` 169 | 5. Open IRIS analytics portal and work with Samples-BI: 170 | http://localhost:52773/csp/user/_DeepSee.UserPortal.Home.zen?$NAMESPACE=USER 171 | 172 | ### Step-by-step Installation 173 | 174 | 1. Clone or [download](http://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=asamples) the repository. If you downloaded a ZIP, extract the files to a directory on the server. You will need to refer to these files' location in step 8. 175 | 2. If you have not yet created a namespace in InterSystems IRIS, follow the [detailed instructions](http://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ASAMPLES_createns) to do so. 176 | 3. In the Management Portal, click System Administration > Security > Applications > Web Applications. 177 | 4. Click the link in the first column of the row /csp/mynamespace where `mynamespace` is the namespace from step 2. 178 | 5. Click the Analytics checkbox and then click Save. 179 | 180 | 6. Open the InterSystems IRIS Terminal. 181 | 7. Enter the following command (replacing `mynamespace` with the namespace from step 2): 182 | ```ObjectScript 183 | ZN "mynamespace" 184 | ``` 185 | 8. Enter the following commands (replacing `full-path-to-Build.SampleBI.cls` with the full path of the `buildsample/Build.SampleBI.cls` file): 186 | 187 | ```ObjectScript 188 | do $system.OBJ.Load("full-path-to-Build.SampleBI.cls","ck") 189 | 190 | do ##class(Build.SampleBI).Build() 191 | ``` 192 | 9. When prompted, enter the full path of the directory to which you downloaded this sample. The method then loads and compiles the code and performs other needed setup steps. 193 | 194 | Now, when you access the Analytics submenu of the Management Portal, this namespace will be listed. For example, you can now use the Analyzer with the cubes that are included within this sample. 195 | 196 | IMPORTANT: If the namespace is not listed when you access the Analytics submenu of the Management Portal, see [Setting Up the Web Application](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=D2IMP_ch_setup#D2IMP_setup_web_app) in the book [Implementing InterSystems IRIS Business Intelligence](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=D2IMP_ch_setup). 197 | 198 | 199 | --------------------------------------------------------------------------------