From 96d0067f2da19860502f69b64030491a79075883 Mon Sep 17 00:00:00 2001 From: Thom Lamb Date: Tue, 12 May 2026 11:33:21 -0500 Subject: [PATCH] chore: deploy initial linqpad queries --- B-24302 UV Case Type Family Updates.linq | 566 ++++++++ CCI Timings.linq | 220 ++++ .../Payroll Opportunity Metric.linq | 79 ++ ...te FactOpportunityMetrics YTD Rollups.linq | 96 ++ CaseType Analytics/CaseType Analysis.linq | 193 +++ CaseType Analytics/CaseTypeDestination.linq | 139 ++ .../CaseTypeFamily Create Corrections.linq | 286 ++++ .../CaseTypeFamily Run Corrections.linq | 79 ++ CaseType Analytics/CaseTypeSource.linq | 142 ++ ...up CaseTypeFamilyMappingICD10 SkipICD.linq | 788 +++++++++++ ...anup CaseTypeFamilyMappingICD10 table.linq | 134 ++ Create CCI StoreProc Unit Tests.linq | 107 ++ Create CPT CaseTypeFamily entries.linq | 171 +++ CrossDB Missing StarterSet Definitions.linq | 527 ++++++++ CrossDBQuery AppVersions.linq | 382 ++++++ CrossDBQuery with useParms.linq | 484 +++++++ CrossDBQuery.linq | 503 +++++++ CultureInfo with examples.linq | 205 +++ DB Query Exceptions.linq | 605 +++++++++ DB Query with Lambda Expressions.linq | 460 +++++++ DDEN SQL Server List.linq | 66 + Dashboard extrapolation.linq | 148 +++ DateTime Differences.linq | 84 ++ DateTime Extensions Tester.linq | 99 ++ DepartmentPatientCensus Analysis.linq | 95 ++ Dev Page Logs.linq | 71 + DimCaseType QA Master.linq | 92 ++ Dynamic JSON object.linq | 9 + Encounter Performance Engine test.linq | 155 +++ Evaluate QVI Bubble Chart.linq | 55 + FPES Encounter Summary analysis.linq | 34 + ...ientEncounterSummary Query Exceptions.linq | 411 ++++++ Find string in table data.linq | 98 ++ .../Test FiscalMonthResolver.linq | 184 +++ Fluent Assertion IAssertionRule Test.linq | 114 ++ Func Test.linq | 70 + Get Report Parms.linq | 83 ++ HackWeek AWS/AWS SDK Basics.linq | 200 +++ .../HackWeek AWS Glue Bucket to Crawlers.linq | 142 ++ ...ek AWS Glue Create Crawler on the fly.linq | 77 ++ .../HackWeek AWS Glue List Bucket.linq | 70 + .../HackWeek AWS Glue List Crawlers.linq | 201 +++ .../HackWeek AWS Glue Run Crawlers.linq | 70 + .../HackWeek AWS Glue Upload Files to S3.linq | 87 ++ Heatmap Facility Deaths.linq | 58 + Heatmap Raw Data.linq | 111 ++ Heatmp Data Linq2Sql.linq | 105 ++ Information Schema.linq | 140 ++ .../Convert CSV file to CTF definitions.linq | 111 ++ JAZZ-14426 Create SQL.linq | 79 ++ Kevin Sql Parsing.linq | 84 ++ ...'s Python queries reversed engineered.linq | 105 ++ Localization DateTime Helpers.linq | 76 ++ MailGun Test with Template Data.linq | 175 +++ MonthNames.linq | 68 + Move files to new name.linq | 95 ++ New StarterSet Cube Parameters.linq | 79 ++ Nursing Census Data Analysis.linq | 161 +++ PayPeriod query.linq | 81 ++ Pokemon API.linq | 65 + Random Color Hex Value.linq | 57 + ScoreDimensions.linq | 143 ++ Snapshot classes testing.linq | 194 +++ Sole Hope/Sole Hope Inventory Complex.linq | 305 +++++ Sole Hope/Sole Hope Inventory Normalized.linq | 237 ++++ Sole Hope/SoleHope Inventory refactoring.linq | 275 ++++ Sole Hope/SoleHopeInventory.linq | 536 ++++++++ SonarQube API/Quboo Integration API.linq | 74 ++ ...SonarQube Just Summarize Issue Counts.linq | 99 ++ SonarQube API/SonarQube WebService API.linq | 1071 +++++++++++++++ SonarQube API/Test the math.linq | 30 + Split text by a phrase.linq | 77 ++ ...Standard Definition Mapping Standards.linq | 23 + .../Starter Set API Definitions Search.linq | 318 +++++ .../Starter Set API Definitions.linq | 134 ++ .../Starter Set API MdxScoreToCube.linq | 138 ++ StarterSet API/Starter Set API Reports.linq | 872 ++++++++++++ .../Starter Set API Validate Endpoint.linq | 96 ++ .../Starter Set API With Report Setup.linq | 908 +++++++++++++ StarterSet API/Starter Set API test.linq | 1172 +++++++++++++++++ .../Starter Set API with Flurl test.linq | 107 ++ ...tarter Set Client StandardDefinitions.linq | 72 + ...ng Report Card Items for DatabaseGuid.linq | 66 + StarterSet API/Starter Set Test.linq | 176 +++ StarterSet API/StarterSet DB Compare.linq | 239 ++++ StarterSet DB compare.linq | 505 +++++++ ...erSet Validator Task Migration Issues.linq | 65 + StrataJazz FileSize Report.linq | 128 ++ Testing the IsFileInDirectory function.linq | 87 ++ TimeZones.linq | 76 ++ UV CaseTypeConfig Parsing.linq | 95 ++ UV Export Analysis.linq | 122 ++ Understanding UNC PayPeriods.linq | 193 +++ ... StrataSphere Reports DefinitionsJson.linq | 88 ++ ...for Starter Set Report Card Validator.linq | 280 ++++ User Role Department PayPeriod query.linq | 241 ++++ UserRole query.linq | 71 + Validate Include and Exclude Regex's.linq | 96 ++ Veracode/Veracode CWE Analytics.linq | 387 ++++++ Veracode/Veracode Module Analytics.linq | 293 +++++ Veracode/Veracode Solution Manager.linq | 80 ++ ...racode parsing report for the modules.linq | 74 ++ Working with Reports SortArgs.linq | 87 ++ archive_pagelogs for reports homr.linq | 68 + cci tables.linq | 121 ++ consolidate CaseTypeFamily information.linq | 398 ++++++ create StrataSphere Mappings.linq | 107 ++ date updates/query1.linq | 16 + date updates/query2.linq | 63 + dynamic query test.linq | 16 + mailgun test with template fake.linq | 174 +++ q1.linq | 58 + q2.linq | 135 ++ q3.linq | 20 + q4.linq | 303 +++++ q5.linq | 120 ++ q6.linq | 89 ++ q7.linq | 89 ++ test.linq | 301 +++++ webex.exe | Bin 0 -> 253968 bytes 120 files changed, 22939 insertions(+) create mode 100644 B-24302 UV Case Type Family Updates.linq create mode 100644 CCI Timings.linq create mode 100644 CI Testing Stuff/Payroll Opportunity Metric.linq create mode 100644 Calculate FactOpportunityMetrics YTD Rollups.linq create mode 100644 CaseType Analytics/CaseType Analysis.linq create mode 100644 CaseType Analytics/CaseTypeDestination.linq create mode 100644 CaseType Analytics/CaseTypeFamily Create Corrections.linq create mode 100644 CaseType Analytics/CaseTypeFamily Run Corrections.linq create mode 100644 CaseType Analytics/CaseTypeSource.linq create mode 100644 CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 SkipICD.linq create mode 100644 CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 table.linq create mode 100644 Create CCI StoreProc Unit Tests.linq create mode 100644 Create CPT CaseTypeFamily entries.linq create mode 100644 CrossDB Missing StarterSet Definitions.linq create mode 100644 CrossDBQuery AppVersions.linq create mode 100644 CrossDBQuery with useParms.linq create mode 100644 CrossDBQuery.linq create mode 100644 CultureInfo with examples.linq create mode 100644 DB Query Exceptions.linq create mode 100644 DB Query with Lambda Expressions.linq create mode 100644 DDEN SQL Server List.linq create mode 100644 Dashboard extrapolation.linq create mode 100644 DateTime Differences.linq create mode 100644 DateTime Extensions Tester.linq create mode 100644 DepartmentPatientCensus Analysis.linq create mode 100644 Dev Page Logs.linq create mode 100644 DimCaseType QA Master.linq create mode 100644 Dynamic JSON object.linq create mode 100644 Encounter Performance Engine test.linq create mode 100644 Evaluate QVI Bubble Chart.linq create mode 100644 FPES Encounter Summary analysis.linq create mode 100644 FactPatientEncounterSummary Query Exceptions.linq create mode 100644 Find string in table data.linq create mode 100644 FiscalMonthResolver/Test FiscalMonthResolver.linq create mode 100644 Fluent Assertion IAssertionRule Test.linq create mode 100644 Func Test.linq create mode 100644 Get Report Parms.linq create mode 100644 HackWeek AWS/AWS SDK Basics.linq create mode 100644 HackWeek AWS/HackWeek AWS Glue Bucket to Crawlers.linq create mode 100644 HackWeek AWS/HackWeek AWS Glue Create Crawler on the fly.linq create mode 100644 HackWeek AWS/HackWeek AWS Glue List Bucket.linq create mode 100644 HackWeek AWS/HackWeek AWS Glue List Crawlers.linq create mode 100644 HackWeek AWS/HackWeek AWS Glue Run Crawlers.linq create mode 100644 HackWeek AWS/HackWeek AWS Glue Upload Files to S3.linq create mode 100644 Heatmap Facility Deaths.linq create mode 100644 Heatmap Raw Data.linq create mode 100644 Heatmp Data Linq2Sql.linq create mode 100644 Information Schema.linq create mode 100644 JAZZ-10828 CTF Definitions/Convert CSV file to CTF definitions.linq create mode 100644 JAZZ-14426 Create SQL.linq create mode 100644 Kevin Sql Parsing.linq create mode 100644 Kevin's Python queries reversed engineered.linq create mode 100644 Localization DateTime Helpers.linq create mode 100644 MailGun Test with Template Data.linq create mode 100644 MonthNames.linq create mode 100644 Move files to new name.linq create mode 100644 New StarterSet Cube Parameters.linq create mode 100644 Nursing Census Data Analysis.linq create mode 100644 PayPeriod query.linq create mode 100644 Pokemon API.linq create mode 100644 Random Color Hex Value.linq create mode 100644 ScoreDimensions.linq create mode 100644 Snapshot classes testing.linq create mode 100644 Sole Hope/Sole Hope Inventory Complex.linq create mode 100644 Sole Hope/Sole Hope Inventory Normalized.linq create mode 100644 Sole Hope/SoleHope Inventory refactoring.linq create mode 100644 Sole Hope/SoleHopeInventory.linq create mode 100644 SonarQube API/Quboo Integration API.linq create mode 100644 SonarQube API/SonarQube Just Summarize Issue Counts.linq create mode 100644 SonarQube API/SonarQube WebService API.linq create mode 100644 SonarQube API/Test the math.linq create mode 100644 Split text by a phrase.linq create mode 100644 StarterSet API/Standard Definition Mapping Standards.linq create mode 100644 StarterSet API/Starter Set API Definitions Search.linq create mode 100644 StarterSet API/Starter Set API Definitions.linq create mode 100644 StarterSet API/Starter Set API MdxScoreToCube.linq create mode 100644 StarterSet API/Starter Set API Reports.linq create mode 100644 StarterSet API/Starter Set API Validate Endpoint.linq create mode 100644 StarterSet API/Starter Set API With Report Setup.linq create mode 100644 StarterSet API/Starter Set API test.linq create mode 100644 StarterSet API/Starter Set API with Flurl test.linq create mode 100644 StarterSet API/Starter Set Client StandardDefinitions.linq create mode 100644 StarterSet API/Starter Set Missing Report Card Items for DatabaseGuid.linq create mode 100644 StarterSet API/Starter Set Test.linq create mode 100644 StarterSet API/StarterSet DB Compare.linq create mode 100644 StarterSet DB compare.linq create mode 100644 StarterSet Validator Task Migration Issues.linq create mode 100644 StrataJazz FileSize Report.linq create mode 100644 Testing the IsFileInDirectory function.linq create mode 100644 TimeZones.linq create mode 100644 UV CaseTypeConfig Parsing.linq create mode 100644 UV Export Analysis.linq create mode 100644 Understanding UNC PayPeriods.linq create mode 100644 Update StrataSphere Reports DefinitionsJson.linq create mode 100644 Update TEScheduleTask for Starter Set Report Card Validator.linq create mode 100644 User Role Department PayPeriod query.linq create mode 100644 UserRole query.linq create mode 100644 Validate Include and Exclude Regex's.linq create mode 100644 Veracode/Veracode CWE Analytics.linq create mode 100644 Veracode/Veracode Module Analytics.linq create mode 100644 Veracode/Veracode Solution Manager.linq create mode 100644 Veracode/Veracode parsing report for the modules.linq create mode 100644 Working with Reports SortArgs.linq create mode 100644 archive_pagelogs for reports homr.linq create mode 100644 cci tables.linq create mode 100644 consolidate CaseTypeFamily information.linq create mode 100644 create StrataSphere Mappings.linq create mode 100644 date updates/query1.linq create mode 100644 date updates/query2.linq create mode 100644 dynamic query test.linq create mode 100644 mailgun test with template fake.linq create mode 100644 q1.linq create mode 100644 q2.linq create mode 100644 q3.linq create mode 100644 q4.linq create mode 100644 q5.linq create mode 100644 q6.linq create mode 100644 q7.linq create mode 100644 test.linq create mode 100644 webex.exe diff --git a/B-24302 UV Case Type Family Updates.linq b/B-24302 UV Case Type Family Updates.linq new file mode 100644 index 0000000..27526f0 --- /dev/null +++ b/B-24302 UV Case Type Family Updates.linq @@ -0,0 +1,566 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var data = @"CaseTypeFamily Name SkipICD ICD10Code MSDRGCode +M-420 1 Cervical Level Anterior Approach FALSE 0RG0070 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0370 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0470 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1070 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1370 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1470 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4070 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4370 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43K0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4470 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44A0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44J0 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44K0 471 +M-421 1 Cervical Level Open Approach FALSE XRG0092 471 +M-421 1 Cervical Level Open Approach FALSE XRG00F3 471 +M-421 1 Cervical Level Open Approach FALSE XRG1092 471 +M-421 1 Cervical Level Open Approach FALSE XRG10F3 471 +M-421 1 Cervical Level Open Approach FALSE XRG4092 471 +M-421 1 Cervical Level Open Approach FALSE XRG40F3 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0071 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG007J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0371 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG037J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0471 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG047J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1071 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG107J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1371 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG137J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1471 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG147J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4071 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG407J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4371 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG437J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43KJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4471 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG447J 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44AJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44J1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44JJ 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44K1 471 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44KJ 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2070 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20A0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20J0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20K0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2370 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23A0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23J0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23K0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2470 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24A0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24J0 471 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24K0 471 +M-424 2+ Cervical Level Open Approach FALSE XRG2092 471 +M-424 2+ Cervical Level Open Approach FALSE XRG20F3 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2071 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG207J 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20AJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20J1 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20JJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20K1 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20KJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2371 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG237J 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23AJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23J1 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23JJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23K1 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23KJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2471 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG247J 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24AJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24J1 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24JJ 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24K1 471 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24KJ 471 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0070 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0370 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0470 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1070 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1370 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1470 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4070 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4370 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43K0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4470 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44A0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44J0 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44K0 472 +M-421 1 Cervical Level Open Approach FALSE XRG0092 472 +M-421 1 Cervical Level Open Approach FALSE XRG00F3 472 +M-421 1 Cervical Level Open Approach FALSE XRG1092 472 +M-421 1 Cervical Level Open Approach FALSE XRG10F3 472 +M-421 1 Cervical Level Open Approach FALSE XRG4092 472 +M-421 1 Cervical Level Open Approach FALSE XRG40F3 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0071 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG007J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0371 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG037J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0471 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG047J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1071 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG107J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1371 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG137J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1471 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG147J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4071 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG407J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4371 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG437J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43KJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4471 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG447J 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44AJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44J1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44JJ 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44K1 472 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44KJ 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2070 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20A0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20J0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20K0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2370 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23A0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23J0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23K0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2470 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24A0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24J0 472 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24K0 472 +M-424 2+ Cervical Level Open Approach FALSE XRG2092 472 +M-424 2+ Cervical Level Open Approach FALSE XRG20F3 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2071 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG207J 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20AJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20J1 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20JJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20K1 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20KJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2371 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG237J 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23AJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23J1 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23JJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23K1 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23KJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2471 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG247J 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24AJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24J1 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24JJ 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24K1 472 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24KJ 472 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0070 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG00K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0370 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG03K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG0470 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG04K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1070 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG10K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1370 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG13K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG1470 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG14K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4070 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG40K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4370 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG43K0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG4470 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44A0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44J0 473 +M-420 1 Cervical Level Anterior Approach FALSE 0RG44K0 473 +M-421 1 Cervical Level Open Approach FALSE XRG0092 473 +M-421 1 Cervical Level Open Approach FALSE XRG00F3 473 +M-421 1 Cervical Level Open Approach FALSE XRG1092 473 +M-421 1 Cervical Level Open Approach FALSE XRG10F3 473 +M-421 1 Cervical Level Open Approach FALSE XRG4092 473 +M-421 1 Cervical Level Open Approach FALSE XRG40F3 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0071 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG007J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG00KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0371 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG037J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG03KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG0471 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG047J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG04KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1071 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG107J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG10KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1371 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG137J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG13KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG1471 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG147J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG14KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4071 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG407J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG40KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4371 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG437J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG43KJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG4471 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG447J 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44AJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44J1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44JJ 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44K1 473 +M-422 1 Cervical Level Posterior Approach FALSE 0RG44KJ 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2070 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20A0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20J0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG20K0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2370 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23A0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23J0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG23K0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG2470 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24A0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24J0 473 +M-423 2+ Cervical Level Anterior Approach FALSE 0RG24K0 473 +M-424 2+ Cervical Level Open Approach FALSE XRG2092 473 +M-424 2+ Cervical Level Open Approach FALSE XRG20F3 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2071 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG207J 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20AJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20J1 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20JJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20K1 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG20KJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2371 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG237J 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23AJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23J1 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23JJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23K1 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG23KJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG2471 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG247J 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24AJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24J1 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24JJ 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24K1 473 +M-425 2+ Cervical Level Posterior Approach FALSE 0RG24KJ 473"; + + var rows = data.Split("\n".ToCharArray()) + .Skip(1) + .ToList() + .ConvertAll(d => new NewCaseTypeFamilyMapping(d.Trim("\r".ToCharArray()).Split('\t'))) + .GroupBy(d => d.CaseTypeFamily, (key, info) => new + { + CaseTypeFamily = key, + data = info.ToList(), + sql = info.Aggregate(new StringBuilder($@" +SELECT @CaseTypeFamilyID = ctf.CaseTypeFamilyID +FROM dss.CaseTypeFamily AS ctf +WHERE ctf.CaseTypeFamilyGlobalID = '{key}' + +INSERT INTO dss.CaseTypeFamilyMappingICD10 ( CaseTypeFamilyID, SkipICD, ICD10Code, MSDRGCode, CaseTypeFamilyVersionID ) +VALUES +"), + (x, y) => x.AppendLine(y.ToString())).ToString().TrimEnd(new[] { '\r', '\n', ',' }), + rollback = $@"DELETE FROM dss.CaseTypeFamilyMappingICD10 +WHERE EXISTS(SELECT 1 FROM dss.CaseTypeFamily AS ctf + WHERE ctf.CaseTypeFamilyGlobalID = '{key}' and CaseTypeFamilyMappingICD10.CaseTypeFamilyID = ctf.CaseTypeFamilyID AND CaseTypeFamilyVersionID = 1) +DELETE FROM dss.CaseTypeFamily WHERE CaseTypeFamilyGlobalID = '{key}' +" + }); + var sqlScript = $@"--Author: tlamb +--Version: 2019.42 +--Forward +DELETE +FROM dss.CaseTypeFamilyMappingICD10 +WHERE EXISTS(SELECT 1 +FROM dss.CaseTypeFamily AS ctf +WHERE ctf.CaseTypeFamilyID = CaseTypeFamilyMappingICD10.CaseTypeFamilyID AND ctf.CaseTypeFamilyGlobalID = 'M-61') +AND CaseTypeFamilyMappingICD10.MSDRGCode IN('471','472','473') +AND CaseTypeFamilyMappingICD10.SkipICD = 1 +AND CaseTypeFamilyMappingICD10.CaseTypeFamilyVersionID = 1 + +INSERT INTO dss.CaseTypeFamily(CaseTypeFamilyGUID, Name, CaseTypeFamilyGlobalID) +VALUES(NEWID(), '1 Cervical Level Anterior Approach', 'M-420'), +(NEWID(), '1 Cervical Level Open Approach', 'M-421'), +(NEWID(), '1 Cervical Level Posterior Approach', 'M-422'), +(NEWID(), '2+ Cervical Level Anterior Approach', 'M-423'), +(NEWID(), '2+ Cervical Level Open Approach', 'M-424'), +(NEWID(), '2+ Cervical Level Posterior Approach', 'M-425') + +DECLARE @CaseTypeFamilyID INT + +{string.Join("\r\n", rows.Select(r => r.sql))} +--Rollback +{string.Join("\r\n", rows.Select(r => r.rollback))}"; + + sqlScript.Dump("script"); + File.WriteAllText(@"D:\git\2019-10-01-11-14 B-24302 UV Case Type Family Updates.sql", sqlScript); + rows.Dump(); + + // var sql = rows.Aggregate(new StringBuilder("DECLARE @CaseTypeFamilyID INT"), + // (x, y) => x.AppendLine( + // data.Aggregate(new StringBuilder($"SELECT @CaseTypeFamilyID = ctf.CaseTypeFamilyID FROM dss.CaseTypeFamily AS ctf WHERE ctf.CaseTypeFamilyGlobalID = '{y.CaseTypeFamily}'"), + // (a, b) => a.AppendLine(b.ToString())).ToString())).ToString(); + // sql.Dump(); +} + +// Define other methods and classes here + +public class NewCaseTypeFamilyMapping +{ + public string CaseTypeFamily { get; set; } + public string Name { get; set; } + internal bool bSkipICD { get; set; } + public int SkipICD => bSkipICD ? 1 : 0; + public string ICD10Code { get; set; } + public string MSDRGCode { get; set; } + + public NewCaseTypeFamilyMapping(string[] data) + { + if (data.Length != 5) + throw new ArgumentException(nameof(data)); + CaseTypeFamily = data[0]; + Name = data[1]; + bSkipICD = bool.Parse(data[2]); + ICD10Code = data[3]; + MSDRGCode = data[4]; + } + + public override string ToString() + { + //return $"\t(@CaseTypeFamilyID, '{Name}', {SkipICD}, '{ICD10Code}', '{MSDRGCode}', 1),"; + return $"\t(@CaseTypeFamilyID, {SkipICD}, '{ICD10Code}', '{MSDRGCode}', 1),"; + } +} \ No newline at end of file diff --git a/CCI Timings.linq b/CCI Timings.linq new file mode 100644 index 0000000..1a30f72 --- /dev/null +++ b/CCI Timings.linq @@ -0,0 +1,220 @@ + + + 4f885e7e-d8bb-427c-a54e-8e3e1c3137a7 + true + IOAK-SQL-LOG-01.sdt.local + jazz log prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +public static string PrimaryUrl => "Opportunities.aspx"; +public static string UrlGroup => "/CCI"; +public static DateTime cutoff { get; set; } = DateTime.Now.AddDays((((int)DateTime.Now.DayOfWeek) * -1) + 1).Date; + +void Main() +{ + RunTimings(); +} + +public void RunTimings() +{ + cutoff = DateTime.Now.AddDays(-30); + var timings = GetTimings(cutoff) + .Where(t => t.Key.Group == 0 && t.Data.Any()); + + var outliers = timings.SelectMany(t => t.Data.Where(d => d.ClientTimeData / 1000.0d > 4.0d)); + outliers.Dump(nameof(outliers)); + + timings + .OrderByDescending(t => t.Key.ClientTimeMax > 4 ? t.Key.ClientTimeMax : 0) + .ThenBy(t => t.Key.Group) + .ThenBy(t => t.Key.Url.Contains(PrimaryUrl) ? "!" : t.Key.Url) + .ThenBy(t => t.Key.Application) + .ThenByDescending(t => t.Key.Date) + .ThenBy(t => t.Key.Browser.StartsWith("IE") ? 0 : 1) + .Dump(); +} + +public IEnumerable GetTimings(DateTime cutoff) +{ + return from log in Archive_PageLogs + where (log.Url.StartsWith(UrlGroup)) + && log.DateTimeStamp > cutoff + group log by new { Group = (log.UserName.StartsWith("sdt\\") ? 1 : 0), log.Url, log.Browser, Date = log.DateTimeStamp.Value.Date, log.Application } into grp + //join dbs in ViewActiveDatabases on grp.FirstOrDefault().DatabaseGuid equals dbs.DatabaseGUID + orderby grp.Key.Group, (grp.FirstOrDefault().ClientTime / 1000) descending, grp.Key.Date descending + select new MetricData + { + Key = new MetricKey + { + Application = grp.Key.Application, + Group = grp.Key.Group, + Url = grp.Key.Url, + Browser = grp.Key.Browser, + Date = grp.Key.Date, + ClientTimeAvg = grp.ToList().Average(g => (g.ClientTime / 1000.0d)) ?? 0.0d, + ClientTimeMin = grp.ToList().Min(g1 => (g1.ClientTime / 1000.0d)) ?? 0.0d, + ClientTimeMax = grp.ToList().Max(g1 => (g1.ClientTime / 1000.0d)) ?? 0.0d, + Count = grp.ToList().Count + }, + Data = grp + .Select(g => new Metric(g.DatabaseGuid.Value, ViewActiveDatabases) + { + UrlParams = g.UrlParams, + UserName = g.UserName, + WebServer = g.WebServer, + ServerTimeData = g.ServerTime ?? 0, + ClientTimeData = g.ClientTime ?? 0, + DatabaseName = g.DatabaseName, + ClientTime = g.ClientTime ?? 0 / 1000.0d, + ClientTimeAvg = grp.ToList().Average(g1 => g1.ClientTime ?? 0.0d / 1000.0d), + ClientTimeMin = grp.ToList().Min(g1 => g1.ClientTime ?? 0.0d / 1000.0d), + ClientTimeMax = grp.ToList().Max(g1 => g1.ClientTime ?? 0.0d / 1000.0d) + }).Where(x => (x.ClientTimeData / 1000.0d) > x.ClientTimeAvg || ((x.ClientTimeData / 1000.0d) > 4.0d)) + }; +} + +// Define other methods and classes here + +public class Metric +{ + public double ClientTime { get; set; } + public double ClientTimeData { get; set; } + public double ClientTimeAvg { get; set; } + public double ClientTimeMin { get; set; } + public double ClientTimeMax { get; set; } + public string WebServer { get; set; } + public string PhysicalName { get; set; } + public Guid DatabaseGuid { get; set; } + public string DatabaseName { get; set; } + public string UserName { get; set; } + public string UrlParams { get; set; } + public int ServerTimeData { get; set; } + public string OrgPin { get; set; } + + public Metric() + { + + } + + public Metric(Guid databaseGuid, Table activeDatabases) + { + DatabaseGuid = databaseGuid; + var activeDatabase = activeDatabases.SingleOrDefault(vad => vad.DatabaseGUID == databaseGuid); + PhysicalName = activeDatabase?.PhysicalName ?? string.Empty; + OrgPin = activeDatabase?.OrgPin ?? string.Empty; + } + + object ToDump() => new + { + ClientTimeMax = new XElement("LINQPad.HTML", + new XElement("div", + new XAttribute("align", "right"), + new XAttribute("style", $"background-color:{(ClientTimeMax > 4.0d ? "red" : (ClientTimeAvg < (ClientTimeData / 1000.0d)) ? "violet" : "white")};"), + $"{ClientTimeMax:n}".PadLeft(10))), + ClientTimeAvg, + ClientTimeMin, + WebServer, + OrgPin, + DatabaseName, + PhysicalName, + UserName, + UrlParams, + ServerTime = $"{ServerTimeData:n0}".PadLeft(10) + }; +} + +public class MetricKey +{ + public string Application { get; set; } + public int Group { get; set; } + public string Browser { get; set; } + public string Url { get; set; } + //public int UrlLength { get; set; } + public DateTime Date { get; set; } + public double ClientTimeAvg { get; set; } + public double ClientTimeMin { get; set; } + public double ClientTimeMax { get; set; } + public int Count { get; set; } + + object ToDump() => new + { + Application, + GroupName = Group == 0 ? "Clients" : "Strata", + Browser, + URL = Url, //.PadRight(UrlLength), + OnDate = Date.ToShortDateString(), + Avg_ClientTime = $"{ClientTimeAvg:N2}", + Min_ClientTime = $"{ClientTimeMin:N2}", + Max_ClientTime = $"{ClientTimeMax:N2}", + Count + }; +} + +public class MetricData +{ + public MetricKey Key { get; set; } + public IEnumerable Data { get; set; } + + object ToDump() => new + { + Group = Key, + Statistics = Data + .OrderBy(d => d.WebServer) + .ThenBy(d => d.DatabaseName) + .ThenBy(d => d.UserName) + .ThenBy(d => d.ClientTimeData) + }; +} \ No newline at end of file diff --git a/CI Testing Stuff/Payroll Opportunity Metric.linq b/CI Testing Stuff/Payroll Opportunity Metric.linq new file mode 100644 index 0000000..def8ffb --- /dev/null +++ b/CI Testing Stuff/Payroll Opportunity Metric.linq @@ -0,0 +1,79 @@ + + +void Main() +{ + var pom = new PayrollOpportunityMetric + { + BaselineMonth01Dollars = 1.0m, + ActualMonth03Dollars = 1.0m, + CommittedMonth06Dollars = 1.0m + }; + pom.BaselineDollars().Dump(); + pom.ActualDollars().Dump(); + pom.CommittedDollars().Dump(); +} + +// Define other methods and classes here + +public class PayrollOpportunityMetric +{ + public decimal BaselineMonth01Dollars { get; set; } = 0.0m; + public decimal BaselineMonth02Dollars { get; set; } = 0.0m; + public decimal BaselineMonth03Dollars { get; set; } = 0.0m; + public decimal BaselineMonth04Dollars { get; set; } = 0.0m; + public decimal BaselineMonth05Dollars { get; set; } = 0.0m; + public decimal BaselineMonth06Dollars { get; set; } = 0.0m; + public decimal BaselineMonth07Dollars { get; set; } = 0.0m; + public decimal BaselineMonth08Dollars { get; set; } = 0.0m; + public decimal BaselineMonth09Dollars { get; set; } = 0.0m; + public decimal BaselineMonth10Dollars { get; set; } = 0.0m; + public decimal BaselineMonth11Dollars { get; set; } = 0.0m; + public decimal BaselineMonth12Dollars { get; set; } = 0.0m; + + public decimal ActualMonth01Dollars { get; set; } = 0.0m; + public decimal ActualMonth02Dollars { get; set; } = 0.0m; + public decimal ActualMonth03Dollars { get; set; } = 0.0m; + public decimal ActualMonth04Dollars { get; set; } = 0.0m; + public decimal ActualMonth05Dollars { get; set; } = 0.0m; + public decimal ActualMonth06Dollars { get; set; } = 0.0m; + public decimal ActualMonth07Dollars { get; set; } = 0.0m; + public decimal ActualMonth08Dollars { get; set; } = 0.0m; + public decimal ActualMonth09Dollars { get; set; } = 0.0m; + public decimal ActualMonth10Dollars { get; set; } = 0.0m; + public decimal ActualMonth11Dollars { get; set; } = 0.0m; + public decimal ActualMonth12Dollars { get; set; } = 0.0m; + + public decimal CommittedMonth01Dollars { get; set; } = 0.0m; + public decimal CommittedMonth02Dollars { get; set; } = 0.0m; + public decimal CommittedMonth03Dollars { get; set; } = 0.0m; + public decimal CommittedMonth04Dollars { get; set; } = 0.0m; + public decimal CommittedMonth05Dollars { get; set; } = 0.0m; + public decimal CommittedMonth06Dollars { get; set; } = 0.0m; + public decimal CommittedMonth07Dollars { get; set; } = 0.0m; + public decimal CommittedMonth08Dollars { get; set; } = 0.0m; + public decimal CommittedMonth09Dollars { get; set; } = 0.0m; + public decimal CommittedMonth10Dollars { get; set; } = 0.0m; + public decimal CommittedMonth11Dollars { get; set; } = 0.0m; + public decimal CommittedMonth12Dollars { get; set; } = 0.0m; +} + +public static class PayrollOpportunityMetricExtensions +{ + public static IEnumerable BaselineDollars(this PayrollOpportunityMetric pom) => + typeof(PayrollOpportunityMetric) + .GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Where(p => p.Name.StartsWith("BaselineMonth") && p.Name.EndsWith("Dollars")) + .Select(dp => (decimal) dp.GetValue(pom, null)); + + public static IEnumerable ActualDollars(this PayrollOpportunityMetric pom) => + typeof(PayrollOpportunityMetric) + .GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Where(p => p.Name.StartsWith("ActualMonth") && p.Name.EndsWith("Dollars")) + .Select(dp => (decimal)dp.GetValue(pom, null)); + + public static IEnumerable CommittedDollars(this PayrollOpportunityMetric pom) => + typeof(PayrollOpportunityMetric) + .GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Where(p => p.Name.StartsWith("CommittedMonth") && p.Name.EndsWith("Dollars")) + .Select(dp => (decimal)dp.GetValue(pom, null)); +} \ No newline at end of file diff --git a/Calculate FactOpportunityMetrics YTD Rollups.linq b/Calculate FactOpportunityMetrics YTD Rollups.linq new file mode 100644 index 0000000..b49009b --- /dev/null +++ b/Calculate FactOpportunityMetrics YTD Rollups.linq @@ -0,0 +1,96 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + DimTimeClasses.Dump(); + + var factList = from fact in FactOpportunityMetrics.ToList() + join fm in DimFiscalMonths.ToList() on fact.FiscalMonthID equals fm.FiscalMonthID + join dtc in DimTimeClasses.ToList() on fact.TimeClassID equals dtc.TimeClassID + select new { fact, fm.SortOrder }; + + var updates = + (from f in factList //.Where(l => l.fact.TimeClassID != 5) + select new + { + f.fact, + AmountYTD = factList + .Where(l => l.fact.OpportunityGUID == f.fact.OpportunityGUID && l.fact.TimeClassID == f.fact.TimeClassID && l.fact.FiscalYearID == f.fact.FiscalYearID && l.SortOrder <= f.SortOrder) + .GroupBy(l => new { l.fact.OpportunityGUID, l.fact.TimeClassID, l.fact.FiscalYearID }) + .Select(l => l.Sum(x => x.fact.Amount)).Single() + }).Where(r => r.AmountYTD != 0).OrderBy(r => r.fact.RowID).ToList(); + + foreach (var update in updates) + { + FactOpportunityMetrics.Where(fom => update.RowID == fom.RowID).ToList() + .ForEach(fact => fact.AmountYTD = update.AmountYTD); + FactOpportunityMetrics.Where(fom => update.RowID == fom.RowID).Dump(); + } + + SubmitChanges(); + FactOpportunityMetrics.Where(fom => fom.AmountYTD != 0) + .Join(ViewOpportunity, f => f.OpportunityGUID, o => o.OpportunityGUID, + (f, o) => new { f.MetricName, f.TimeClassID, f.FiscalYearID, f.FiscalMonthID, f.Amount, f.AmountYTD, o.Name, o.OpportunityType }).Dump(); +} + + +// Define other methods and classes here \ No newline at end of file diff --git a/CaseType Analytics/CaseType Analysis.linq b/CaseType Analytics/CaseType Analysis.linq new file mode 100644 index 0000000..10fbc55 --- /dev/null +++ b/CaseType Analytics/CaseType Analysis.linq @@ -0,0 +1,193 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.ComponentModel + + +void Main() +{ + var caseTypes = (from fpes in FactPatientEncounterSummaries + join ves in VariationEncounterSavings on fpes.EncounterID equals ves.EncounterID + join vo in VariationOpportunities on ves.OpportunityGUID equals vo.OpportunityGUID + join config in Configurations on vo.ConfigurationGUID equals config.ConfigurationGUID + join cte in CaseTypeEntities on vo.CaseTypeEntityID equals cte.CaseTypeEntityID + join dct in DimCaseTypes on cte.CaseTypeGUID equals dct.MemberGUID + join d in DimMSDRGs on fpes.ReportingDRGID equals d.MSDRGID into da + from e in da.DefaultIfEmpty() + join f in DimAPRDRGs on fpes.APDRGID equals f.APRDRGID into fa + from g in fa.DefaultIfEmpty() + join cpt in DimCPTs on fpes.PrimaryCPTID equals cpt.CPTID into cpta + from ca in cpta.DefaultIfEmpty() + where config.FiscalYearID == 2020 + select new + { + vo.ConfigurationGUID, + config.FiscalYearID, + dct.CaseTypeId, + dct.Name, + CCMCCCategory = e.CCMCCCategory ?? "", + SOI = g.APRSOI ?? "", + ROM = g.APRROM ?? "", + CPTCode = ca.CPTCode ?? "", + CaseTypeConfig = JsonConvert.DeserializeObject(dct.CaseTypeConfigJSON) + }) + .Distinct() + .Select(t => new + { + t.ConfigurationGUID, + t.FiscalYearID, + t.CaseTypeId, + t.Name, + t.CCMCCCategory, + t.SOI, + t.ROM, + t.CPTCode, + t.CaseTypeConfig.AgeCohortIDInclusions, + t.CaseTypeConfig.PhysicianIDExclusions, + t.CaseTypeConfig.StandardDeviationExcludedTypeEnum, + t.CaseTypeConfig.LengthOfStayThreshold, + t.CaseTypeConfig.SOIROMInclusions, + t.CaseTypeConfig.CCMCCCategories, + t.CaseTypeConfig.CPTCodes, + t.CaseTypeConfig.PatientTypeRollupIDInclusions, + t.CaseTypeConfig.PhysicianMinVolume + }) + .OrderBy(t => t.Name); + caseTypes.Dump(); +} + +// Define other methods and classes here +public const string CCMCCCATEGORY_CC = "CC"; +public const string CCMCCCATEGORY_MCC = "MCC"; +public const string CCMCCCATEGORY_WO = "W/O"; +public const string CCMCCCATEGORY_NA = "N/A"; +public const string CCMCCCATEGORY_CCMCC = "CC/MCC"; + + +public enum CCMCCCategoryTypes +{ + /// + /// No Category + /// + [Description("")] + None, + /// + /// Complication or Comorbidity + /// + [Description(CCMCCCATEGORY_CC)] + CC, + /// + /// Major Complication or Comorbidity + /// + [Description(CCMCCCATEGORY_MCC)] + MCC, + /// + /// Without Complication or Comorbidity OR Major Complication or Comorbidity + /// + [Description(CCMCCCATEGORY_WO)] + WO, + /// + /// Not Available + /// + [Description(CCMCCCATEGORY_NA)] + NA, + /// + /// Both Complication or Comorbidity AND Major Complication or Comorbidity + /// + [Description(CCMCCCATEGORY_CCMCC)] + CCMCC +} + +public class SOIROMInclusion +{ + public string SOI { get; } + public string ROM { get; } + + public SOIROMInclusion(string soi, string rom) + { + SOI = soi; + ROM = rom; + } +} + +public class CaseTypeDRGConfiguration +{ + public int PhysicianMinVolume { get; set; } + public List AgeCohortIDInclusions { get; set; } + public List PhysicianIDExclusions { get; set; } + public int StandardDeviationExcludedTypeEnum { get; set; } + public int LengthOfStayThreshold { get; set; } + public List PatientTypeRollupIDInclusions { get; set; } + public List SOIROMInclusions { get; set; } + public HashSet CCMCCCategories { get; set; } + public HashSet CPTCodes { get; set; } + + public CaseTypeDRGConfiguration() + { + PhysicianMinVolume = 0; + AgeCohortIDInclusions = new List(); + PhysicianIDExclusions = new List(); + PatientTypeRollupIDInclusions = new List(); + StandardDeviationExcludedTypeEnum = 0; + LengthOfStayThreshold = 0; + CCMCCCategories = new HashSet(); + CPTCodes = new HashSet(); + } + +} \ No newline at end of file diff --git a/CaseType Analytics/CaseTypeDestination.linq b/CaseType Analytics/CaseTypeDestination.linq new file mode 100644 index 0000000..de79a47 --- /dev/null +++ b/CaseType Analytics/CaseTypeDestination.linq @@ -0,0 +1,139 @@ + + + 870a756b-af44-4db4-b004-58ff41318b3a + true + P9900-SQL-11.sdt.local + jazz tst GM DSS Share Training Master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private IEnumerable existing_versions; +private IEnumerable existing_migrations; +private IEnumerable existing_families; +private IEnumerable existing_mappings; + +void Main() +{ + Step1(); + + existing_migrations.Dump(); + existing_versions.Dump(); + existing_families.Count().Dump(); + existing_mappings.Count().Dump(); + var documentFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(existing_migrations)}.json"), JsonConvert.SerializeObject(existing_migrations, Newtonsoft.Json.Formatting.Indented)); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(existing_versions)}.json"), JsonConvert.SerializeObject(existing_versions, Newtonsoft.Json.Formatting.Indented)); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(existing_families)}.json"), JsonConvert.SerializeObject(existing_families, Newtonsoft.Json.Formatting.Indented)); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(existing_mappings)}.json"), JsonConvert.SerializeObject(existing_mappings, Newtonsoft.Json.Formatting.Indented)); +} + +// Define other methods and classes here +private void Step1() +{ + existing_migrations = from ml in MigrationLogs where ml.DateTimeStamp > new DateTime(2018, 11, 16) && ml.Name.Replace(" ", "").Contains("CaseType") orderby ml.DateTimeStamp descending select ml.Name; + existing_versions = from ctfv in CaseTypeFamilyVersions select new VersionInfo(ctfv.CaseTypeFamilyVersionID, ctfv.Name, ctfv.StartDate, ctfv.EndDate); + existing_families = from ctf in CaseTypeFamilies select new FamilyInfo(ctf.CaseTypeFamilyGlobalID, ctf.Name, ctf.CaseTypeFamilyID); + existing_mappings = (from ctfm in CaseTypeFamilyMappingICD10s + join family in CaseTypeFamilies on ctfm.CaseTypeFamilyID equals family.CaseTypeFamilyID + where ctfm.CaseTypeFamilyVersionID == 1 + select new MappingInfo(family.CaseTypeFamilyGlobalID, ctfm.SkipICD, ctfm.ICD10Code, ctfm.MSDRGCode)).Distinct(); +} + + +public class VersionInfo +{ + public int CaseTypeFamilyVersionId { get; set; } + public string Name { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + + public VersionInfo(int id, string name, DateTime start, DateTime end) + { + CaseTypeFamilyVersionId = id; + Name = name; + StartDate = start; + EndDate = end; + } +} + +public class FamilyInfo +{ + public int CaseTypeFamilyID { get; set; } + public string CaseTypeFamilyGlobalID { get; set; } + public string Name { get; set; } + + public FamilyInfo(string caseTypeFamilyGlobalID, string name, int caseTypeFamilyID) + { + CaseTypeFamilyID = caseTypeFamilyID; + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + Name = name; + } +} + +public class MappingInfo +{ + public string CaseTypeFamilyGlobalID { get; set; } + public bool SkipICD { get; set; } + public string ICD10Code { get; set; } + public string MSDRGCode { get; set; } + + public MappingInfo(string caseTypeFamilyGlobalID, bool skipICD, string icd10Code, string msdrgCode) + { + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + SkipICD = skipICD; + ICD10Code = icd10Code; + MSDRGCode = msdrgCode; + } +} diff --git a/CaseType Analytics/CaseTypeFamily Create Corrections.linq b/CaseType Analytics/CaseTypeFamily Create Corrections.linq new file mode 100644 index 0000000..3aa91dd --- /dev/null +++ b/CaseType Analytics/CaseTypeFamily Create Corrections.linq @@ -0,0 +1,286 @@ + + + 870a756b-af44-4db4-b004-58ff41318b3a + true + P9900-SQL-11.sdt.local + jazz tst GM non DSS Share Training Master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private IEnumerable correct_versions; +private IEnumerable correct_migrations; +private IEnumerable correct_families; +private IEnumerable correct_mappings; +private IEnumerable existing_versions; +private IEnumerable existing_migrations; +private IEnumerable existing_families; +private IEnumerable existing_mappings; + +void Main() +{ + //var cts = Util.GetMyQueries().FirstOrDefault(u => u.FilePath.EndsWith("CaseTypeSource.linq")); + //var connStr = cts.GetConnectionInfo().DatabaseInfo.GetCxString(); + Step1(); + Step2(); + + var versions = (from cf in correct_versions + join ef in existing_versions on cf.CaseTypeFamilyVersionId equals ef.CaseTypeFamilyVersionId into cef + from ef in cef.DefaultIfEmpty() + select new { cf, ef }).ToList(); + versions.Dump(nameof(versions)); + var migrations = (from cf in correct_migrations + join ef in existing_migrations on cf equals ef into cef + from ef in cef.DefaultIfEmpty() + select new { cf, ef }).ToList(); + var migrationDeletes = (from cf in existing_migrations + join ef in correct_migrations on cf equals ef into cef + from ef in cef.DefaultIfEmpty() + select new { cf, ef }).ToList(); + var families = (from cf in correct_families + join ef in existing_families on cf.CaseTypeFamilyGlobalID equals ef.CaseTypeFamilyGlobalID into cef + from ef in cef.DefaultIfEmpty() + select new { cf, ef }).ToList(); + var familyDeletes = (from cf in existing_families + join ef in correct_families on cf.CaseTypeFamilyGlobalID equals ef.CaseTypeFamilyGlobalID into cef + from ef in cef.DefaultIfEmpty() + select new { cf, ef }).ToList(); + var mappings = (from cm in correct_mappings + join em in existing_mappings on new { cm.CaseTypeFamilyGlobalID, cm.SkipICD, cm.ICD10Code, cm.MSDRGCode } + equals new { em.CaseTypeFamilyGlobalID, em.SkipICD, em.ICD10Code, em.MSDRGCode } into cem + from em in cem.DefaultIfEmpty() + select new { cm, em }).ToList(); + var mappingDeletes = (from cm in existing_mappings + join em in correct_mappings on new { cm.CaseTypeFamilyGlobalID, cm.SkipICD, cm.ICD10Code, cm.MSDRGCode } + equals new { em.CaseTypeFamilyGlobalID, em.SkipICD, em.ICD10Code, em.MSDRGCode } into cem + from em in cem.DefaultIfEmpty() + select new { cm, em }).ToList(); + + var documentFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + var sql = versions.Where(f => f.ef == null) + .Aggregate(@"", (x, y) => $@"{x} +INSERT INTO [dss].[CaseTypeFamilyVersion] (CaseTypeFamilyVersionId, Name, StartDate, EndDate) +SELECT '{y.cf.CaseTypeFamilyVersionId}', '{y.cf.Name}', '{y.cf.StartDate:G}', '{y.cf.EndDate:G}' +WHERE NOT EXISTS (SELECT 1 FROM [dss].[CaseTypeFamilyVersion] WHERE CaseTypeFamilyVersionId = '{y.cf.CaseTypeFamilyVersionId}'); +"); + if (File.Exists(Path.Combine(documentFolder, $"Case Type Family Corrections 1 ({this.Connection.Database}).sql"))) + File.Delete(Path.Combine(documentFolder, $"Case Type Family Corrections 1 ({this.Connection.Database}).sql")); + if (!string.IsNullOrEmpty(sql.Trim())) + File.WriteAllText(Path.Combine(documentFolder, $"Case Type Family Corrections 1 ({this.Connection.Database}).sql"), sql); + + sql = versions.Where(f => f.ef != null + && ((f.cf.Name != f.ef.Name + && f.cf.Name.Replace("And", "&") != f.ef.Name + && f.cf.Name.Replace(" And ", "&") != f.ef.Name) + || (f.cf.StartDate != f.ef.StartDate) + || (f.cf.EndDate != f.ef.EndDate))) + .Aggregate(@"", (x, y) => $@"{x} +UPDATE [dss].[CaseTypeFamilyVersion] +SET Name = '{y.cf.Name}', StartDate = '{y.cf.StartDate:G}', EndDate = '{y.cf.EndDate:G}' +WHERE CaseTypeFamilyVersionId = '{y.cf.CaseTypeFamilyVersionId}'; -- current name = {y.ef.Name} +"); + if (File.Exists(Path.Combine(documentFolder, $"Case Type Family Corrections 2 ({this.Connection.Database}).sql"))) + File.Delete(Path.Combine(documentFolder, $"Case Type Family Corrections 2 ({this.Connection.Database}).sql")); + if (!string.IsNullOrEmpty(sql.Trim())) + File.WriteAllText(Path.Combine(documentFolder, $"Case Type Family Corrections 2 ({this.Connection.Database}).sql"), sql); + + sql = families.Where(f => f.ef == null) + .Aggregate(@"", (x, y) => $@"{x} +INSERT INTO [dss].[CaseTypeFamily] (CaseTypeFamilyGlobalID, Name) +SELECT '{y.cf.CaseTypeFamilyGlobalID}', '{y.cf.Name}' +WHERE NOT EXISTS (SELECT 1 FROM [dss].[CaseTypeFamily] WHERE CaseTypeFamilyGlobalID = '{y.cf.CaseTypeFamilyGlobalID}'); +"); + if (File.Exists(Path.Combine(documentFolder, $"Case Type Family Corrections 3 ({this.Connection.Database}).sql"))) + File.Delete(Path.Combine(documentFolder, $"Case Type Family Corrections 3 ({this.Connection.Database}).sql")); + if (!string.IsNullOrEmpty(sql.Trim())) + File.WriteAllText(Path.Combine(documentFolder, $"Case Type Family Corrections 3 ({this.Connection.Database}).sql"), sql); + + sql = families.Where(f => f.ef != null + && (f.cf.Name != f.ef.Name + && f.cf.Name.Replace("And", "&") != f.ef.Name + && f.cf.Name.Replace(" And ", "&") != f.ef.Name)) + .Aggregate(@"", (x, y) => $@"{x} +UPDATE [dss].[CaseTypeFamily] +SET Name = '{y.cf.Name}' +WHERE CaseTypeFamilyGlobalID = '{y.cf.CaseTypeFamilyGlobalID}'; -- current name = {y.ef.Name} +"); + if (File.Exists(Path.Combine(documentFolder, $"Case Type Family Corrections 4 ({this.Connection.Database}).sql"))) + File.Delete(Path.Combine(documentFolder, $"Case Type Family Corrections 4 ({this.Connection.Database}).sql")); + if (!string.IsNullOrEmpty(sql.Trim())) + File.WriteAllText(Path.Combine(documentFolder, $"Case Type Family Corrections 4 ({this.Connection.Database}).sql"), sql); + + var insert = sql = mappings.Where(f => f.em == null).Any() + ? @"INSERT INTO [dss].[CaseTypeFamilyMappingICD10] ([CaseTypeFamilyID], [SkipICD], [ICD10Code], [MSDRGCode], [CaseTypeFamilyVersionID]) +" : ""; + var selects = mappings.Where(f => f.em == null) + .Select((y, idx) => new { query = $@"SELECT [CaseTypeFamilyID], {(y.cm.SkipICD ? 1 : 0)}, '{y.cm.ICD10Code}', '{y.cm.MSDRGCode}', 1 FROM [dss].[CaseTypeFamily] WHERE [CaseTypeFamilyGlobalID] = '{y.cm.CaseTypeFamilyGlobalID}'", idx }) + .GroupBy(g => g.idx / 1000, (g, d) => d) + .Select(z => insert + string.Join("\r\nUNION ALL\r\n", z.Select(y => y.query))); + Enumerable.Range(0, 999).ToList() + .ForEach(y => + { + if (File.Exists(Path.Combine(documentFolder, $"Case Type Family Corrections 3{y:000} ({this.Connection.Database}).sql"))) + File.Delete(Path.Combine(documentFolder, $"Case Type Family Corrections 3{y:000} ({this.Connection.Database}).sql")); + }); + selects.ForEach((x, y) => File.WriteAllText(Path.Combine(documentFolder, $"Case Type Family Corrections 3{y:000} ({this.Connection.Database}).sql"), x)); + + versions.Where(f => f.ef == null).Dump("missing versions"); + migrations.Where(f => f.ef == null).Dump("missing migrations"); + migrationDeletes.Where(f => f.ef == null).Dump("migrations to delete"); + families.Where(f => f.ef == null).Dump("missing families"); + families.Where(f => f.ef != null + && (f.cf.Name != f.ef.Name + && f.cf.Name.Replace("And", "&") != f.ef.Name + && f.cf.Name.Replace(" And ", "&") != f.ef.Name)).Dump("families to update"); + familyDeletes.Where(f => f.ef == null).Dump("families to detele"); + mappings.Where(f => f.em == null).Dump("missing mappings"); + mappings.Where(f => f.em != null && (f.cm.SkipICD != f.em.SkipICD || f.cm.ICD10Code != f.em.ICD10Code || f.cm.MSDRGCode != f.em.MSDRGCode)).Dump("mappings to update"); + mappingDeletes.Where(f => f.em == null).Dump("mappings to delete"); + +} + + +// Define other methods and classes here + +/// +/// Connect to P2680-SQL-03 - jazz prd Mercy Health 20160308.1 +/// +private void Step1(string connectionString) +{ + var currentConnection = this.Connection.ConnectionString; + this.Connection.ConnectionString = connectionString; + this.Connection.Dump(); + + correct_migrations = from ml in MigrationLogs + where ml.Name.Replace(" ", "").Contains("CaseType") //&& ml.DateTimeStamp > new DateTime(2018, 11, 16) + orderby ml.DateTimeStamp descending + select ml.Name; + correct_versions = from ctfv in CaseTypeFamilyVersions select new VersionInfo(ctfv.CaseTypeFamilyVersionID, ctfv.Name, ctfv.StartDate, ctfv.EndDate); + correct_families = from ctf in CaseTypeFamilies select new FamilyInfo(ctf.CaseTypeFamilyGlobalID, ctf.Name, ctf.CaseTypeFamilyID); + correct_mappings = (from ctfm in CaseTypeFamilyMappingICD10s + join family in CaseTypeFamilies on ctfm.CaseTypeFamilyID equals family.CaseTypeFamilyID + where ctfm.CaseTypeFamilyVersionID == 1 + select new MappingInfo(family.CaseTypeFamilyGlobalID, ctfm.SkipICD, ctfm.ICD10Code, ctfm.MSDRGCode)).Distinct(); + + this.Connection.ConnectionString = currentConnection; +} + +private void Step1() +{ + var documentFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + correct_migrations = JsonConvert.DeserializeObject>(File.ReadAllText(Path.Combine(documentFolder, $"{nameof(correct_migrations)}.json"))); + correct_versions = JsonConvert.DeserializeObject>(File.ReadAllText(Path.Combine(documentFolder, $"{nameof(correct_versions)}.json"))); + correct_families = JsonConvert.DeserializeObject>(File.ReadAllText(Path.Combine(documentFolder, $"{nameof(correct_families)}.json"))); + correct_mappings = JsonConvert.DeserializeObject>(File.ReadAllText(Path.Combine(documentFolder, $"{nameof(correct_mappings)}.json"))); +} + +private void Step2() +{ + existing_migrations = from ml in MigrationLogs + where ml.Name.Replace(" ", "").Contains("CaseType") //&& ml.DateTimeStamp > new DateTime(2018, 11, 16) + orderby ml.DateTimeStamp + select ml.Name; + existing_versions = from ctfv in CaseTypeFamilyVersions select new VersionInfo(ctfv.CaseTypeFamilyVersionID, ctfv.Name, ctfv.StartDate, ctfv.EndDate); + existing_families = from ctf in CaseTypeFamilies select new FamilyInfo(ctf.CaseTypeFamilyGlobalID, ctf.Name, ctf.CaseTypeFamilyID); + existing_mappings = (from ctfm in CaseTypeFamilyMappingICD10s + join family in CaseTypeFamilies on ctfm.CaseTypeFamilyID equals family.CaseTypeFamilyID + where ctfm.CaseTypeFamilyVersionID == 1 + select new MappingInfo(family.CaseTypeFamilyGlobalID, ctfm.SkipICD, ctfm.ICD10Code, ctfm.MSDRGCode)).Distinct(); +} + +public class VersionInfo +{ + public int CaseTypeFamilyVersionId { get; set; } + public string Name { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + + public VersionInfo(int id, string name, DateTime start, DateTime end) + { + CaseTypeFamilyVersionId = id; + Name = name; + StartDate = start; + EndDate = end; + } +} + +public class FamilyInfo +{ + public int CaseTypeFamilyID { get; set; } + public string CaseTypeFamilyGlobalID { get; set; } + public string Name { get; set; } + + public FamilyInfo(string caseTypeFamilyGlobalID, string name, int caseTypeFamilyID) + { + CaseTypeFamilyID = caseTypeFamilyID; + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + Name = name; + } +} + +public class MappingInfo +{ + public string CaseTypeFamilyGlobalID { get; set; } + public bool SkipICD { get; set; } + public string ICD10Code { get; set; } + public string MSDRGCode { get; set; } + + public MappingInfo(string caseTypeFamilyGlobalID, bool skipICD, string icd10Code, string msdrgCode) + { + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + SkipICD = skipICD; + ICD10Code = icd10Code; + MSDRGCode = msdrgCode; + } +} \ No newline at end of file diff --git a/CaseType Analytics/CaseTypeFamily Run Corrections.linq b/CaseType Analytics/CaseTypeFamily Run Corrections.linq new file mode 100644 index 0000000..42bf361 --- /dev/null +++ b/CaseType Analytics/CaseTypeFamily Run Corrections.linq @@ -0,0 +1,79 @@ + + + 870a756b-af44-4db4-b004-58ff41318b3a + true + P9900-SQL-11.sdt.local + jazz tst GM non DSS Share Training Master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var documentFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + var files = Directory.GetFiles(documentFolder, "Case Type Family Corrections*.sql") + .Select(d => Path.GetFileName(d)) + .OrderBy(d => d) + .ToList(); + files.ForEach(f => + { + "".Dump(f); + var query = File.ReadAllText(Path.Combine(documentFolder, f)); + this.ExecuteCommand(query); + }); + + +} + +// Define other methods and classes here diff --git a/CaseType Analytics/CaseTypeSource.linq b/CaseType Analytics/CaseTypeSource.linq new file mode 100644 index 0000000..6439e51 --- /dev/null +++ b/CaseType Analytics/CaseTypeSource.linq @@ -0,0 +1,142 @@ + + + 94a82e0d-b8c1-4789-96cc-f34a75ba3c45 + true + P2980-SQL-03.sdt.local + jazz prd Mercy Health 20160308.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private IEnumerable correct_versions; +private IEnumerable correct_migrations; +private IEnumerable correct_families; +private IEnumerable correct_mappings; + +void Main() +{ + Step1(); + + correct_migrations.Dump(); + correct_versions.Dump(); + correct_families.Count().Dump(); + correct_mappings.Count().Dump(); + var documentFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(correct_migrations)}.json"), JsonConvert.SerializeObject(correct_migrations, Newtonsoft.Json.Formatting.Indented)); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(correct_versions)}.json"), JsonConvert.SerializeObject(correct_versions, Newtonsoft.Json.Formatting.Indented)); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(correct_families)}.json"), JsonConvert.SerializeObject(correct_families, Newtonsoft.Json.Formatting.Indented)); + File.WriteAllText(Path.Combine(documentFolder, $"{nameof(correct_mappings)}.json"), JsonConvert.SerializeObject(correct_mappings, Newtonsoft.Json.Formatting.Indented)); +} + +// Define other methods and classes here +private void Step1() +{ + correct_migrations = from ml in MigrationLogs + where ml.Name.Replace(" ", "").Contains("CaseType") //&& ml.DateTimeStamp > new DateTime(2018, 11, 16) + orderby ml.DateTimeStamp descending + select ml.Name; + correct_versions = from ctfv in CaseTypeFamilyVersions select new VersionInfo(ctfv.CaseTypeFamilyVersionID, ctfv.Name, ctfv.StartDate, ctfv.EndDate); + correct_families = from ctf in CaseTypeFamilies select new FamilyInfo(ctf.CaseTypeFamilyGlobalID, ctf.Name, ctf.CaseTypeFamilyID); + correct_mappings = (from ctfm in CaseTypeFamilyMappingICD10s + join family in CaseTypeFamilies on ctfm.CaseTypeFamilyID equals family.CaseTypeFamilyID + where ctfm.CaseTypeFamilyVersionID == 1 + select new MappingInfo(family.CaseTypeFamilyGlobalID, ctfm.SkipICD, ctfm.ICD10Code, ctfm.MSDRGCode)).Distinct(); +} + + +public class VersionInfo +{ + public int CaseTypeFamilyVersionId { get; set; } + public string Name { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + + public VersionInfo(int id, string name, DateTime start, DateTime end) + { + CaseTypeFamilyVersionId = id; + Name = name; + StartDate = start; + EndDate = end; + } +} + +public class FamilyInfo +{ + public int CaseTypeFamilyID { get; set; } + public string CaseTypeFamilyGlobalID { get; set; } + public string Name { get; set; } + + public FamilyInfo(string caseTypeFamilyGlobalID, string name, int caseTypeFamilyID) + { + CaseTypeFamilyID = caseTypeFamilyID; + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + Name = name; + } +} + +public class MappingInfo +{ + public string CaseTypeFamilyGlobalID { get; set; } + public bool SkipICD { get; set; } + public string ICD10Code { get; set; } + public string MSDRGCode { get; set; } + + public MappingInfo(string caseTypeFamilyGlobalID, bool skipICD, string icd10Code, string msdrgCode) + { + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + SkipICD = skipICD; + ICD10Code = icd10Code; + MSDRGCode = msdrgCode; + } +} diff --git a/CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 SkipICD.linq b/CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 SkipICD.linq new file mode 100644 index 0000000..2e8a5c6 --- /dev/null +++ b/CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 SkipICD.linq @@ -0,0 +1,788 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private string text = @"1 558 M-296 +1 987 M-345 +1 895 M-16 +1 670 M-304 +1 445 M-98 +1 599 A-19 +1 505 M-125 +1 033 M-322 +1 247 M-229 +1 881 M-90 +1 294 M-100 +1 605 M-305 +1 208 M-367 +1 163 M-177 +1 248 M-230 +1 182 M-262 +1 637 A-6 +1 287 M-337 +1 815 M-264 +1 344 M-194 +1 387 A-13 +1 281 M-5 +1 985 M-249 +1 923 M-354 +1 896 M-17 +1 920 M-338 +1 230 A-21 +1 975 M-142 +1 504 M-125 +1 754 M-187 +1 950 M-13 +1 263 M-321 +1 579 M-362 +1 034 M-231 +1 595 A-18 +1 574 M-277 +1 472 M-61 +1 258 M-56 +1 776 M-245 +1 200 M-241 +1 336 A-24 +1 603 M-58 +1 334 M-253 +1 729 M-217 +1 816 M-264 +1 158 M-89 +1 485 M-163 +1 310 M-328 +1 555 M-274 +1 600 M-204 +1 661 M-162 +1 849 A-26 +1 939 M-346 +1 389 M-131 +1 187 M-239 +1 410 M-283 +1 712 M-297 +1 333 M-253 +1 186 M-239 +1 510 M-222 +1 343 M-29 +1 865 A-32 +1 790 M-116 +1 183 M-178 +1 501 M-280 +1 578 M-276 +1 809 M-182 +1 781 M-25 +1 750 M-214 +1 150 M-108 +1 350 M-152 +1 770 M-281 +1 335 A-24 +1 453 M-27 +1 053 M-288 +1 474 M-21 +1 424 M-353 +1 709 M-228 +1 178 M-261 +1 561 M-72 +1 100 M-270 +1 710 M-228 +1 556 M-274 +1 416 M-65 +1 123 M-201 +1 935 M-203 +1 516 M-357 +1 355 M-140 +1 215 M-137 +1 189 M-251 +1 094 M-34 +1 064 M-59 +1 685 M-8 +1 617 M-22 +1 759 A-9 +1 464 M-323 +1 725 M-36 +1 664 M-193 +1 789 M-344 +1 167 M-361 +1 292 A-12 +1 800 A-29 +1 509 M-30 +1 668 M-304 +1 069 A-31 +1 594 A-27 +1 882 M-202 +1 663 M-193 +1 314 A-22 +1 767 M-318 +1 489 M-164 +1 871 M-273 +1 688 M-161 +1 959 M-359 +1 667 M-248 +1 455 M-27 +1 675 M-355 +1 006 M-169 +1 155 M-213 +1 228 A-21 +1 059 M-88 +1 760 M-118 +1 843 M-220 +1 903 M-111 +1 070 M-60 +1 031 M-322 +1 495 M-109 +1 779 M-1 +1 928 M-129 +1 179 M-261 +1 222 M-55 +1 371 M-180 +1 381 M-70 +1 949 M-13 +1 298 M-52 +1 792 M-247 +1 285 M-6 +1 308 M-328 +1 221 M-285 +1 657 M-159 +1 264 M-349 +1 028 A-28 +1 639 A-6 +1 511 M-222 +1 500 M-280 +1 695 M-158 +1 180 M-262 +1 176 A-25 +1 674 M-355 +1 037 M-115 +1 945 M-105 +1 597 A-19 +1 478 M-41 +1 841 M-172 +1 869 M-150 +1 306 M-75 +1 948 M-368 +1 570 M-329 +1 654 A-15 +1 138 M-196 +1 908 M-358 +1 434 M-66 +1 538 M-291 +1 559 M-72 +1 965 M-356 +1 202 M-48 +1 557 M-296 +1 689 M-160 +1 244 M-234 +1 446 M-98 +1 101 M-270 +1 723 M-189 +1 225 M-54 +1 835 M-4 +1 549 M-272 +1 262 M-57 +1 964 M-356 +1 956 M-167 +1 376 A-7 +1 437 M-188 +1 135 M-275 +1 352 M-152 +1 984 M-249 +1 226 M-53 +1 283 M-6 +1 218 M-284 +1 370 A-16 +1 540 M-209 +1 191 M-77 +1 534 M-120 +1 602 M-58 +1 982 M-114 +1 148 M-102 +1 838 M-62 +1 007 M-171 +1 293 A-12 +1 097 M-287 +1 280 M-5 +1 498 M-110 +1 746 M-317 +1 830 M-199 +1 272 M-334 +1 067 M-205 +1 458 M-290 +1 078 M-146 +1 147 M-102 +1 345 M-194 +1 071 M-60 +1 295 M-100 +1 096 M-34 +1 235 M-49 +1 385 A-13 +1 624 M-279 +1 499 M-110 +1 922 M-354 +1 234 M-50 +1 423 M-353 +1 989 M-345 +1 715 M-186 +1 765 M-84 +1 934 M-128 +1 550 M-272 +1 137 M-196 +1 918 M-242 +1 056 M-86 +1 958 M-359 +1 868 M-150 +1 207 M-366 +1 250 M-232 +1 442 M-99 +1 826 M-342 +1 671 M-311 +1 062 M-293 +1 201 M-241 +1 165 M-177 +1 257 M-371 +1 441 M-99 +1 565 M-198 +1 421 M-139 +1 886 M-35 +1 625 M-298 +1 085 M-306 +1 354 M-140 +1 074 M-80 +1 038 M-115 +1 113 A-20 +1 791 M-246 +1 393 M-210 +1 660 M-162 +1 857 M-244 +1 904 M-278 +1 630 M-351 +1 940 M-346 +1 197 M-153 +1 241 M-282 +1 273 M-333 +1 330 M-175 +1 390 M-131 +1 195 M-240 +1 456 M-290 +1 814 M-264 +1 713 M-308 +1 866 A-32 +1 553 M-43 +1 010 A-23 +1 747 M-317 +1 804 M-360 +1 125 M-211 +1 473 M-61 +1 700 M-216 +1 755 M-187 +1 341 M-29 +1 933 M-113 +1 340 M-28 +1 496 M-109 +1 023 M-339 +1 289 M-7 +1 239 M-282 +1 963 M-356 +1 149 M-101 +1 159 M-89 +1 618 M-22 +1 515 M-357 +1 309 M-328 +1 193 M-240 +1 444 M-98 +1 242 M-234 +1 076 A-33 +1 577 M-276 +1 432 M-66 +1 029 A-28 +1 032 M-322 +1 691 M-313 +1 300 M-233 +1 016 M-32 +1 408 M-283 +1 435 M-188 +1 622 M-279 +1 870 M-271 +1 249 M-230 +1 502 M-280 +1 388 M-131 +1 662 M-193 +1 757 A-9 +1 828 M-342 +1 282 M-5 +1 604 M-305 +1 854 M-341 +1 573 M-277 +1 793 M-127 +1 554 M-43 +1 699 M-216 +1 058 M-88 +1 008 M-225 +1 339 M-28 +1 902 M-111 +1 223 M-55 +1 542 M-227 +1 115 M-286 +1 592 A-27 +1 269 M-332 +1 316 A-22 +1 846 M-63 +1 231 M-51 +1 768 M-319 +1 707 A-17 +1 665 M-248 +1 268 M-332 +1 883 M-235 +1 483 M-183 +1 856 M-244 +1 497 M-109 +1 134 M-350 +1 955 A-5 +1 642 M-76 +1 332 M-253 +1 181 M-262 +1 129 M-181 +1 976 M-142 +1 947 M-368 +1 139 M-269 +1 151 M-108 +1 718 M-218 +1 842 M-172 +1 440 M-97 +1 052 M-288 +1 040 M-363 +1 156 M-213 +1 229 A-21 +1 544 M-227 +1 847 M-63 +1 844 M-220 +1 382 M-70 +1 862 M-243 +1 077 M-146 +1 641 M-207 +1 572 M-329 +1 780 A-8 +1 744 M-85 +1 658 M-159 +1 927 M-112 +1 820 M-173 +1 216 M-284 +1 643 M-106 +1 166 M-361 +1 290 M-7 +1 233 M-50 +1 855 M-341 +1 083 M-307 +1 824 M-174 +1 411 M-64 +1 696 M-158 +1 304 A-128 +1 409 M-283 +1 055 M-200 +1 102 M-136 +1 655 A-15 +1 378 M-130 +1 520 M-335 +1 666 M-248 +1 687 M-161 +1 693 M-312 +1 079 M-146 +1 099 M-287 +1 307 M-75 +1 914 M-370 +1 327 M-369 +1 539 M-209 +1 722 M-189 +1 546 A-4 +1 133 M-350 +1 834 M-4 +1 969 M-340 +1 368 A-16 +1 375 A-7 +1 894 M-18 +1 297 M-52 +1 457 M-290 +1 717 M-218 +1 004 M-301 +1 383 M-309 +1 303 M-31 +1 065 M-59 +1 724 M-189 +1 728 M-151 +1 801 A-29 +1 255 M-371 +1 014 M-19 +1 672 M-311 +1 880 M-2 +1 291 A-12 +1 863 M-243 +1 232 M-51 +1 017 M-32 +1 256 M-371 +1 130 M-181 +1 063 M-293 +1 417 M-166 +1 296 M-52 +1 748 M-119 +1 475 M-21 +1 438 M-97 +1 734 M-252 +1 745 M-85 +1 970 M-340 +1 545 A-4 +1 593 A-27 +1 566 M-198 +1 425 M-353 +1 897 M-17 +1 487 M-163 +1 974 M-142 +1 627 M-298 +1 560 M-72 +1 562 M-197 +1 575 M-277 +1 177 M-261 +1 068 M-205 +1 271 M-334 +1 337 A-24 +1 782 M-26 +1 198 M-153 +1 203 M-48 +1 629 M-351 +1 199 M-241 +1 486 M-163 +1 714 M-308 +1 095 M-34 +1 623 M-279 +1 087 M-306 +1 917 M-242 +1 876 M-347 +1 716 M-186 +1 227 M-53 +1 380 M-70 +1 988 M-345 +1 517 M-357 +1 188 M-239 +1 152 M-223 +1 374 A-7 +1 284 M-6 +1 506 M-185 +1 711 M-297 +1 082 M-307 +1 802 M-360 +1 116 M-157 +1 795 M-206 +1 184 M-178 +1 395 M-210 +1 420 M-139 +1 073 M-80 +1 628 M-351 +1 921 M-338 +1 794 M-343 +1 114 A-20 +1 606 M-195 +1 286 M-337 +1 596 A-18 +1 035 M-231 +1 260 M-57 +1 415 M-65 +1 887 M-219 +1 471 M-61 +1 829 M-199 +1 645 M-106 +1 217 M-284 +1 146 M-102 +1 346 M-194 +1 758 A-9 +1 708 A-17 +1 827 M-342 +1 192 M-77 +1 351 M-152 +1 329 M-175 +1 205 M-221 +1 338 M-28 +1 541 M-209 +1 245 M-14 +1 749 M-214 +1 463 M-323 +1 086 M-306 +1 164 M-177 +1 769 M-364 +1 342 M-29 +1 601 M-204 +1 808 M-182 +1 386 A-13 +1 204 M-263 +1 810 M-182 +1 243 M-234 +1 454 M-27 +1 259 M-56 +1 837 M-62 +1 117 M-157 +1 433 M-66 +1 288 M-7 +1 813 M-68 +1 075 A-33 +1 576 M-276 +1 885 M-250 +1 692 M-313 +1 981 M-114 +1 224 M-54 +1 652 A-14 +1 261 M-57 +1 512 M-222 +1 372 M-180 +1 799 A-29 +1 686 M-161 +1 190 M-77 +1 638 A-6 +1 042 M-363 +1 465 M-323 +1 313 A-3 +1 414 M-65 +1 024 M-339 +1 598 A-19 +1 246 M-229 +1 519 M-335 +1 236 M-49 +1 547 A-4 +1 543 M-227 +1 946 M-105 +1 777 M-104 +1 419 M-166 +1 477 M-41 +1 840 M-172 +1 533 M-120 +1 659 M-162 +1 270 M-334 +1 872 M-273 +1 864 A-10 +1 154 M-213 +1 479 M-41 +1 909 M-358 +1 823 M-174 +1 503 M-125 +1 194 M-240 +1 735 M-252 +1 951 M-352 +1 030 A-28 +1 583 M-190 +1 656 M-159 +1 418 M-166 +1 690 M-160 +1 379 M-130 +1 326 M-369 +1 929 M-129 +1 518 M-335 +1 311 M-24 +1 157 M-89 +1 436 M-188 +1 041 M-363 +1 673 M-355 +1 582 M-190 +1 413 M-64 +1 853 M-341 +1 756 M-187 +1 124 M-211 +1 168 M-361 +1 901 M-111 +1 089 M-74 +1 581 M-362 +1 036 M-231 +1 775 M-327 +1 373 M-180 +1 913 M-370 +1 669 M-304 +1 301 M-233 +1 122 A-1 +1 312 M-294 +1 653 A-15 +1 315 A-22 +1 571 M-329 +1 039 M-115 +1 697 M-310 +1 369 A-16 +1 858 M-244 +1 551 M-192 +1 412 M-64 +1 265 M-15 +1 061 M-293 +1 084 M-307 +1 825 M-174 +1 088 M-74 +1 727 M-151 +1 240 M-282 +1 443 M-99 +1 054 M-200 +1 778 A-30 +1 730 M-217 +1 836 M-4 +1 185 M-178 +1 072 M-60 +1 220 M-285 +1 377 M-130 +1 175 A-25 +1 121 A-1 +1 353 M-140 +1 057 M-86 +1 867 M-150 +1 919 M-338 +1 274 M-333 +1 726 M-36 +1 644 M-106 +1 537 M-291 +1 552 M-192 +1 983 M-114 +1 328 M-369 +1 821 M-173 +1 564 M-198 +1 626 M-298 +1 098 M-287 +1 219 M-285 +1 060 M-88 +1 394 M-210 +1 384 M-309 +1 822 M-173 +1 136 M-275 +1 607 M-195 +1 153 M-223 +1 905 M-278 +1 616 M-22 +1 331 M-175 +1 066 M-59 +1 580 M-362 +1 907 M-358 +1 196 M-153 +1 476 M-21 +1 941 M-346 +1 548 M-272 +1 698 M-216 +1 439 M-97 +1 206 M-221 +1 916 A-2 +1 305 A-128 +1 803 M-360 +1 103 M-136 +1 251 M-232 +1 766 M-84 +1 915 A-2 +1 299 M-233 +1 563 M-197 +1 848 M-63 +1 986 M-249 +1 694 M-312 +1 957 M-359 +1 977 M-143 +1 845 M-220 +1 090 M-74 +1 488 M-164 +1 302 M-31 +1 839 M-62 +1 422 M-139 +1 761 M-118 +1 640 M-207 +1 774 M-330 +1 0 783 M-412 +1 0 784 M-412 +1 0 785 M-412 +1 0 786 M-413 +1 0 787 M-413 +1 0 788 M-413 +1 0 805 M-414 +1 0 806 M-414 +1 0 807 M-414 +1 0 817 M-415 +1 0 818 M-415 +1 0 819 M-415 +1 0 831 M-416 +1 0 832 M-416 +1 0 833 M-416 +1 0 796 M-318 +1 0 797 M-318 +1 0 798 M-318"; + +void Main() +{ + var mappings = text.Replace("\r\n", "\r").Split('\r') + .Where(r => !string.IsNullOrEmpty(r) && r.Split('\t').Length == 4) // There must be exactly 4 columns in each row of data + .Select(x => + { + var column = x.Split('\t'); + return new CaseTypeFamilyMapping(column[0], column[1], column[2], column[3], 0); + }); + mappings.Where(m => m != null).OrderBy(m => m.SkipICD).ThenBy(m => m.ICD10Code).ThenBy(m => m.MSDRGCode).ThenBy(m => m.GlobalID).Dump(); +} + +public class CaseTypeFamilyMapping +{ + public bool SkipICD { get; set; } + public string ICD10Code { get; set; } + public string MSDRGCode { get; set; } + public string GlobalID { get; set; } + public int CaseTypeFamilyId { get; set; } + + public CaseTypeFamilyMapping(string skipICD, string icd10Code, string msdrgCode, string globalID, int caseTypeFamilyId) + { + if (!bool.TryParse(skipICD, out bool skipped)) skipped = false; + SkipICD = (skipICD == "1"); + ICD10Code = icd10Code; + MSDRGCode = msdrgCode; + GlobalID = globalID; + //CaseTypeFamilyId = caseTypeFamilyId; + } + +} diff --git a/CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 table.linq b/CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 table.linq new file mode 100644 index 0000000..6b64b51 --- /dev/null +++ b/CaseType Analytics/Cleanup CaseTypeFamilyMappingICD10 table.linq @@ -0,0 +1,134 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var grps = CaseTypeFamilyMappingICD10s +.Where(ctf => ctf.CaseTypeFamilyVersionID == 2) +.GroupBy(ctf => new { ctf.CaseTypeFamilyID, ctf.ICD10Code }) +.OrderBy(grp => grp.Key.CaseTypeFamilyID) +.ThenBy(grp => grp.Key.ICD10Code) +.Select(grp => new { grp.Key.CaseTypeFamilyID, grp.Key.ICD10Code, count = grp.Count() }); + +var grpBreak = 100000; +var pageSize = 10000; +foreach (var grp in grps) +{ + grp.Dump(); + if (grp.count > grpBreak) + { + var subgrps = CaseTypeFamilyMappingICD10s + .Where(ctf => ctf.CaseTypeFamilyVersionID == 2) + .GroupBy(ctf => new { ctf.CaseTypeFamilyID, ctf.ICD10Code, ctf.MSDRGCode }) + .OrderBy(subgrp => subgrp.Key.CaseTypeFamilyID) + .ThenBy(subgrp => subgrp.Key.ICD10Code) + .ThenBy(subgrp => subgrp.Key.MSDRGCode) + .Select(subgrp => new { subgrp.Key.CaseTypeFamilyID, subgrp.Key.ICD10Code, subgrp.Key.MSDRGCode, count = subgrp.Count() }); + + foreach (var subgrp in subgrps) + { + subgrp.Dump(); + var subgrpremove = from mapping in CaseTypeFamilyMappingICD10s + where mapping.CaseTypeFamilyID == subgrp.CaseTypeFamilyID + && mapping.ICD10Code == subgrp.ICD10Code + && mapping.MSDRGCode == subgrp.MSDRGCode + && mapping.CaseTypeFamilyVersionID == 2 + select mapping; + + if (subgrpremove.Any()) + { + var pages = ((subgrp.count + (pageSize - 1)) / pageSize); + Enumerable.Range(0, pages).ToList() + .ForEach(page => + { + $"{(page + 1)} of {pages}".Dump(); + var workSet = subgrpremove.Skip(page * pageSize).Take(pageSize).ToList(); + CaseTypeFamilyMappingICD10s.DeleteAllOnSubmit(workSet); + SubmitChanges(); + }); + } + } + continue; + } + var remove = from mapping in CaseTypeFamilyMappingICD10s + where mapping.CaseTypeFamilyID == grp.CaseTypeFamilyID + && mapping.ICD10Code == grp.ICD10Code + && mapping.CaseTypeFamilyVersionID == 2 + select mapping; + + if (remove.Any()) + { + var pages = ((grp.count + (pageSize - 1)) / pageSize); + Enumerable.Range(0, pages).ToList() + .ForEach(page => + { + $"{(page + 1)} of {pages}".Dump(); + var workSet = remove.Skip(page * pageSize).Take(pageSize).ToList(); + CaseTypeFamilyMappingICD10s.DeleteAllOnSubmit(workSet); + SubmitChanges(); + }); + } +} \ No newline at end of file diff --git a/Create CCI StoreProc Unit Tests.linq b/Create CCI StoreProc Unit Tests.linq new file mode 100644 index 0000000..d752e28 --- /dev/null +++ b/Create CCI StoreProc Unit Tests.linq @@ -0,0 +1,107 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var routines = @"procCleanupOpportunities +procDeleteAllData +procDeleteDimensionData +procEpicADTInitializeDepartmentPatientCensus +procInsertDimensionDefaults +procOptimizationRebuildIndexesDimensions +procPatientCensusDiscardIncorrectEntries +procPatientEncounterSummaryUpdateCaseTypeId +procPopulateCustomOpportunitySavings +procPopulateDepartmentPatientCensus +procPopulateDepartmentPatientCensusFromCerner +procPopulateDepartmentPatientCensusFromMeditech +procPopulateDepartmentPatientCensusFromStarADT +procPopulateDepartmentPatientDailyCensus +procPopulatePhysicianQualityMetrics +procSampleCaseTypeFamilyMetricsAll +procSampleChargeCodeConfigs +procSampleMSDRGCaseTypeFamilyMetrics +procSampleNursingDepartments +procSampleNursingMonthlyVolume +procSampleUNSPSCRollup +procUpdateDimInitiative +procUpdateDimOpportunity +procUpdateFactOpportunityMetric +procUpdateFactOpportunitySavings".Replace("\r\n", "\r").Split('\r'); +var bools = new[] { true }; //, false }; +var groups = new[] { 2, 3 }; +var variations = (from b in bools + from g in groups + from r in routines + select new { b = b && g != 1, g, r, q = g == 1 ? "NoQuery" : g == 2 ? "DataSet" : g == 3 ? "Datatable" : "Scalar" }) + .Distinct() + .Where(v => v.r != "procPopulateCustomOpportunitySavings") + .OrderBy(o => o.q) + .ThenBy(o => o.r) + .ThenByDescending(o => o.b).ToList(); + +//variations.Dump(); + +variations.ForEach(v => $@" [Test] + public void TestxCci{v.r}{v.g}_{v.q}() + {{ + var contextMock = new Mock().As(); + + using (contextMock.InScope()) + {{ + {(v.b ? "var ts = (int)TimeSpan.FromMinutes(5).TotalSeconds;\r\n " : "")}Action act = () => {v.r}.Execute{v.q}({(v.b ? "Guid.NewGuid()" : "")}); + act.Should().NotThrow(); + }} + + contextMock.VerifyStoredProc<{v.r}>({(v.b ? "TimeSpan.FromMinutes(5), " : "")}Times.Never()); + }} +".Dump()); \ No newline at end of file diff --git a/Create CPT CaseTypeFamily entries.linq b/Create CPT CaseTypeFamily entries.linq new file mode 100644 index 0000000..d69d265 --- /dev/null +++ b/Create CPT CaseTypeFamily entries.linq @@ -0,0 +1,171 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var opcptcodefile = @"D:\Users\tlamb\Downloads\OP CTF_03232020.txt"; +var opcptcodelist = File.ReadAllLines(opcptcodefile); +var opcptcodes = opcptcodelist.Skip(1).Select(o => new { CaseTypeFamily = o.Split('\t')[0], CPTCode = o.Split('\t')[1].Trim() }); + +var newCaseTypeFamily = from op in opcptcodes + join ctf in CaseTypeFamilies on op.CaseTypeFamily equals ctf.Name into joined + from j in joined.DefaultIfEmpty() + where j == null + select op.CaseTypeFamily; + +var newCaseTypeFamilies = +@"--Author: tlamb +--Version: 2020.21 +--Forward +update pes set pes.MSDRGCaseTypeFamilyID = 0, pes.APRDRGCaseTypeFamilyID = 0 +from [clientdss].[FactPatientEncounterSummary] pes +INNER JOIN fw.DimPatientType pt on pt.PatientTypeID = pes.PatientTypeID +INNER JOIN fw.DimPatientTypeRollup ptr on pt.PatientTypeRollupID = ptr.PatientTypeRollupID +where ptr.Type <> 'Inpatient'; +GO +DELETE FROM dss.CaseTypeFamily WHERE CaseTypeFamilyGlobalID LIKE 'O-%'; +GO +DELETE FROM dss.CaseTypeFamilyMappingCPT; +GO +" + +string.Join("\r\n", opcptcodes +.Select(o => o.CaseTypeFamily) +.Distinct().OrderBy(ctf => ctf) +.Select((ctf, i) => new {i, value = $"\t( NEWID(), N'{ctf}', N'O-{(i + 1):0000}' )"}) +.GroupBy(ctf => (int)ctf.i / 100, (g, d) => string.Join(",\r\n", d.Select(v => v.value))) +.Select(ctf => $"INSERT INTO dss.CaseTypeFamily ( CaseTypeFamilyGUID, Name, CaseTypeFamilyGlobalID )\r\nVALUES\r\n{ctf};\r\nGO")) + +@" +DECLARE @CaseTypeFamilyVersionID INT; +SELECT @CaseTypeFamilyVersionID = CaseTypeFamilyVersionID FROM dss.CaseTypeFamilyVersion AS ctfv WHERE GETDATE() BETWEEN ctfv.StartDate AND ctfv.EndDate; +" + +string.Join("\r\n", opcptcodes +.Select(o => $@"INSERT INTO dss.CaseTypeFamilyMappingCPT ( CaseTypeFamilyID, CPTCode, CaseTypeFamilyVersionID ) +SELECT CaseTypeFamilyID, '{o.CPTCode}', @CaseTypeFamilyVersionID +FROM dss.CaseTypeFamily AS ctf WHERE ctf.Name = '{o.CaseTypeFamily}'")) + @" +GO +--Rollback +update pes set pes.MSDRGCaseTypeFamilyID = 0, pes.APRDRGCaseTypeFamilyID = 0 +from [clientdss].[FactPatientEncounterSummary] pes +INNER JOIN fw.DimPatientType pt on pt.PatientTypeID = pes.PatientTypeID +INNER JOIN fw.DimPatientTypeRollup ptr on pt.PatientTypeRollupID = ptr.PatientTypeRollupID +where ptr.Type <> 'Inpatient'; +GO +DELETE FROM dss.CaseTypeFamily WHERE CaseTypeFamilyGlobalID LIKE 'O-%'; +GO +DELETE FROM dss.CaseTypeFamilyMappingCPT; +GO +"; +File.WriteAllText(@"D:\Git\jazz\Migrations\CCI\2020-03-25-15-34 D-09502 OP CaseTypeFamily Definitions 2.sql", newCaseTypeFamilies); +newCaseTypeFamilies.Dump(nameof(newCaseTypeFamilies)); + +/* +var dbResults = from ctfmc in CaseTypeFamilyMappingCPTs + join ctf in CaseTypeFamilies on ctfmc.CaseTypeFamilyID equals ctf.CaseTypeFamilyID + join ctfv in CaseTypeFamilyVersions on ctfmc.CaseTypeFamilyVersionID equals ctfv.CaseTypeFamilyVersionID + select new { ctfmc.CPTCode, ctf.CaseTypeFamilyID, ctf.Name }; + +var missing = from op in opcptcodes + join db in dbResults on op.CPTCode equals db.CPTCode into joined + from j in joined.DefaultIfEmpty() + where j == null || + (j != null && op.CaseTypeFamily != j.Name) + select new + { + op.CPTCode, + NewName = op.CaseTypeFamily, + OldCaseTypeFamilyID = j?.CaseTypeFamilyID ?? -1, + OldName = j?.Name ?? "" + }; + +var updates = from m in missing + join ctf in CaseTypeFamilies on m.NewName equals ctf.Name into joined + from j in joined.DefaultIfEmpty() + select new + { + m.CPTCode, + m.NewName, + NewCaseTypeFamilyID = j?.CaseTypeFamilyID ?? -1, + m.OldCaseTypeFamilyID, + m.OldName + }; + +updates +.Where(u => u.NewCaseTypeFamilyID != -1) +.OrderBy(u => u.NewCaseTypeFamilyID) +.Dump(nameof(updates)); + +updates +.Where(u => u.NewCaseTypeFamilyID == -1) +.Count().Dump("Count"); + +updates +.Where(u => u.NewCaseTypeFamilyID == -1) +.OrderBy(u => u.NewCaseTypeFamilyID) +.Dump("New Case Type Family"); + +var oldCaseTypeFamilies = updates +.Where(u => u.NewCaseTypeFamilyID != -1) +.Select(u => u.NewName).Distinct().OrderBy(u => u); +oldCaseTypeFamilies.Dump(nameof(oldCaseTypeFamilies)); + +var newCaseTypeFamilies = updates +.Where(u => u.NewCaseTypeFamilyID == -1) +.Select(u => u.NewName).Distinct().OrderBy(u => u); +newCaseTypeFamilies.Dump(nameof(newCaseTypeFamilies)); +*/ \ No newline at end of file diff --git a/CrossDB Missing StarterSet Definitions.linq b/CrossDB Missing StarterSet Definitions.linq new file mode 100644 index 0000000..6e01d1d --- /dev/null +++ b/CrossDB Missing StarterSet Definitions.linq @@ -0,0 +1,527 @@ + + + db640701-a1c5-4177-9f03-5152d093ffa7 + true + D0011-sql-01.sdt.local + jazz tst StrataSphere 20191104.1 + true + + RestSharp + RestSharp + Newtonsoft.Json + System.Data.Common + + +private string BaseUrl = "https://localhost:44325/api/v1/"; //"https://api-dev.sdt.local/starterset-api/api/v1/"; //"https://starterset-api.dev.k8s.sdt.local/api/v1/"; +private List TheGrade = new List(); + +#region *** Enumerations *** + +public enum QueryRegions +{ + Production, + Training, + Oak, + Dev +} + +#endregion + +#region *** Options *** + +public static QueryRegions queryRegion = QueryRegions.Dev; +public static string crossDBQueryPath = @"D:\CrossDBQueries"; // This is the path to find the queries +public static bool dumpOptions = false; // This flag will dumpt this set of options +public static bool dumpSmcSql = false; // This flag will dump the smc sql to the result +public static bool dumpDBList = false; // This flag will dump the databases to the result +public static bool dumpQueries = false; // This flag will dump the queries to the result +public static bool dumpDBExclusions = false; // This flag will dump the db and server exclusions +public static bool dumpDBTargets = false; // This flag will dump the db and server targets +public static bool dumpAppVersions = false; // This flag will dump the app versions used in the queryRegion +public static bool dumpAppVersionTargets = false; // This flag will dump the app versions targets +public static bool excludeExceptions = true; +public static bool queryCompress = false; +public static bool flatten = true; // This will flatten all of the results into a single list +public static bool showStopWatch = false; +public static bool noQueries = false; // This will stop the CrossDBQuery without running the queries + +#endregion + +public static Parms parms = new Parms +{ + name = "FY2020" +}; + +#region *** Database Selection *** + +public static string[] appVersions = { // This is a list of appVersions to filter for in the database list + //"2019.42" +}; + +public static string[] serverExclusions = { // This is a list of servers to exclude from the database list + @"paonsql19.sdt.local\instance1", + @"paonsql17.sdt.local\instance1", + @"p0555-sql-01.sdt.local\instance1", + "P0000-sql-01.sdt.local", + "P9900-SQL-03.sdt.local", + "P9900-sql-05.sdt.local" +}; + +public static string[] dbExclusions = { // This is a list of database physical names to exclude from the database list +}; +public static string[] targetOrgPins = { // This is a list of org pins to target in the database list +}; +public static string[] targetServers = { // This is a list of servers to target in the database list +}; +public static string[] targetDBs = { // This is a list of database physicial names to target in the database list +//"jazz tst Aultman 20200417.1" +}; + +#endregion *** Options *** + +#region *** SMC Settings and queries *** + +public static string smcSql => @"SELECT di.ServerName, di.DatabaseGUID, di.DatabaseName, di.PhysicalName, di.OrgPin, di.AppVersion, di.Description +FROM [dbo].[viewDatabaseInfo] di +WHERE 1=1" ++ (queryRegion == QueryRegions.Dev +? @" + AND di.PhysicalName like 'jazz%'" +: $@" + AND di.PhysicalName like 'jazz {(queryRegion != QueryRegions.Production ? "tst" : "prd")}%' + AND di.ServerName like 'p%'"); +public static string smcServer { get; set; } +public static string smcDB { get; set; } + +#endregion + +#region *** Program variables and settings *** + +public static IOrderedEnumerable databases => GetDatabases(); + +#endregion + +public void OptionsDump() +{ + var options = new + { + queryRegion, + crossDBQueryPath, + dumpOptions, + dumpSmcSql, + dumpDBList, + dumpQueries, + dumpDBExclusions, + dumpDBTargets, + dumpAppVersions, + dumpAppVersionTargets, + excludeExceptions, + queryCompress, + flatten, + showStopWatch, + noQueries + }; + options.Dump(nameof(options)); +} + +public class Parms +{ + public string name { get; set; } +} + +void Main() +{ + RestClient client = new RestClient(); + var definitions = GetList(client, "Definitions"); + var definitionTranslations = GetList(client, "DefinitionTranslations"); + + var work = definitions + .GroupBy(d => new + { + d.HierarchyGuid, + d.DimensionGuid, + d.AttributeGuid, + d.HierarchyId, + d.DimensionId, + d.AttributeId + }, (g, d) => new WorkDto + { + DefinitionGuids = d.Select(x => x.Id).ToList(), + HierarchyGuid = g.HierarchyGuid, + DimensionGuid = g.DimensionGuid, + AttributeGuid = g.AttributeGuid, + HierarchyId = g.HierarchyId, + DimensionId = g.DimensionId, + AttributeId = g.AttributeId, + Name = g.AttributeId == "a177cc88-e329-44e0-9063-2d9b59af51b2" + ? "Department" + : g.AttributeId == "f23654b3-149f-490a-a366-fca35f57d66a" + ? "EntityID" + : g.AttributeId == "MRDEPTENTITY" + ? "Entity" + : string.Empty + }) + .Distinct() + .OrderBy(d => d.DimensionId) + .ThenBy(d => d.AttributeId) + .ToList(); + + DoTheDumping(); + + databases + //.Where(d => d.DatabaseName == "Aultman") + .OrderBy(d => d.DatabaseName) + .ThenBy(d => d.OrgPin) + .ThenBy(d => d.PhysicalName) + .ToList() + .ForEach(db => + { + FindMissing(work, db); + }); + var theWork = TheGrade + .Distinct().ToList(); + //theWork.Dump(nameof(theWork)); + theWork.RemoveAll(tg => tg.AttributeGUID == Guid.Empty || tg.AttributeId == tg.AttributeGUID.ToString()); + JsonConvert.SerializeObject(theWork, Newtonsoft.Json.Formatting.Indented).Dump("json"); +} + +public void FindMissing(List work, Database database) +{ + var db = new TypedDataContext(database.ConnectionString); + try + { + var dimensions = work.Select(w => w.DimensionGuid).Distinct(); + var Score = + (from d in db.ScoreDimensions + join dg in db.ScoreDimensionGroups on d.DimensionGUID equals dg.DimensionGUID + join a in db.ScoreAttributes on dg.DimensionGroupGUID equals a.DimensionGroupGUID + where dimensions.Contains(d.DimensionGUID) + select new ScoreInfo(database.DatabaseName, database.DatabaseGuid, d.FriendlyName, d.DefaultHierarchyGUID, d.DimensionGUID, a.FriendlyName, a.AttributeGUID)) + .ToList(); + work.ToList() + .ForEach(w => + { + var scores = Score.Where(sw => sw.DimensionGUID == w.DimensionGuid).ToList(); + if (!scores.Any()) + return; + var s = scores.FirstOrDefault(sw => sw.AttributeGUID == w.AttributeGuid); + if (s != null) + { + w.score = s; + return; + } + s = scores.FirstOrDefault(sw => sw.AttributeName == w.Name); + if (s == null) + { + w.score = scores.FirstOrDefault(); + } + w.ByName = true; + w.score = s; + }); + var missing = work.Where(w => w.score == null || w.ByName).ToList(); + missing.ForEach(m => + { + if (m.score == null) + m.score = new ScoreInfo(database.DatabaseName, database.DatabaseGuid, "", Guid.Empty, Guid.Empty, "", Guid.Empty); + m.score.DefinitionGuids = new List(); + m.score.DefinitionGuids.AddRange(m.DefinitionGuids ?? new List()); + }); + var grades = missing.SelectMany(m => m.score.DefinitionGuids + .Select(dg => new DefinitionTranslationDto(dg, m.score.DatabaseName, m.score.DatabaseGuid, m.AttributeId, m.score.AttributeName, m.score.AttributeGUID))); + + TheGrade.AddRange(grades); + //missing.Dump(database.DatabaseName); + } + catch (Exception e) + { + + } + +} + +[JsonObject(MemberSerialization.OptIn)] +public class DefinitionTranslationDto +{ + [JsonProperty] + public Guid DefinitionId { get; set; } + public string DatabaseName { get; set; } + [JsonProperty] + public Guid DatabaseGuid { get; set; } + public string AttributeId { get; set; } + public string AttributeName {get;set;} + [JsonProperty] + public Guid AttributeGUID { get; set; } + + public DefinitionTranslationDto(Guid definitionId, string databaseName, Guid databaseGuid, string attributeId, string attributeName, Guid attributeGuid) + { + DefinitionId = definitionId; + DatabaseName = databaseName; + DatabaseGuid = databaseGuid; + AttributeId = attributeId; + AttributeName = attributeName; + AttributeGUID = attributeGuid; + } +} + +public class ScoreInfo +{ + public string DatabaseName { get; set; } + public Guid DatabaseGuid { get; set; } + public string DimensionName { get; set; } + public Guid HierarchyGUID { get; set; } + public Guid DimensionGUID { get; set; } + public string AttributeName { get; set; } + public Guid AttributeGUID { get; set; } + public List DefinitionGuids { get; set; } = new List(); + + public ScoreInfo(string databaseName, Guid databaseGuid, string dimensionName, Guid hierarchyGUID, Guid dimensionGUID, string attributeName, Guid attributeGUID) + { + DatabaseName = databaseName; + DatabaseGuid = databaseGuid; + DimensionName = dimensionName; + HierarchyGUID = hierarchyGUID; + DimensionGUID = dimensionGUID; + AttributeName = attributeName; + AttributeGUID = attributeGUID; + } + +} + +public class WorkDto +{ + public Guid HierarchyGuid { get; set; } + public Guid DimensionGuid { get; set; } + public Guid AttributeGuid { get; set; } + public string HierarchyId { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public string Name { get; set; } + public List DefinitionGuids { get; set; } + public bool ByName { get; set; } = false; + public ScoreInfo score { get; set; } +} + +public void DumpScore() +{ + var Score = + (from d in ScoreDimensions + join dg in ScoreDimensionGroups on d.DimensionGUID equals dg.DimensionGUID + join a in ScoreAttributes on dg.DimensionGroupGUID equals a.DimensionGroupGUID + select new { DimensionName = d.FriendlyName, d.DefaultHierarchyGUID, d.DimensionGUID, AttributeName = a.FriendlyName, a.AttributeGUID }); + + Score + .GroupBy(sdm => new { sdm.DimensionName, sdm.DefaultHierarchyGUID, sdm.DimensionGUID }, (g, d) => new + { + Dimension = new + { + g.DimensionName, + g.DimensionGUID, + g.DefaultHierarchyGUID, + Attributes = d.Count() + }, + Attributes = d.Select(sdm => new + { + sdm.AttributeName, + sdm.AttributeGUID + }) + .OrderBy(sdm => sdm.AttributeName) + .ToList() + }) + .OrderBy(ss => ss.Dimension.DimensionName) + .Dump(); +} + +// Define other methods and classes here + +#region *** Other classes *** + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content, + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Error.Message.Dump(); + args.ErrorContext.Handled = true; + } + }); +} + +public class DefinitionDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public Guid HierarchyGuid { get; set; } + public Guid DimensionGuid { get; set; } + public Guid AttributeGuid { get; set; } + public string HierarchyId { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + + public DefinitionDto() + { + } +} + +public class Database +{ + public string Server { get; set; } + public Guid DatabaseGuid { get; set; } + public string DatabaseName { get; set; } + public string PhysicalName { get; set; } + public string OrgPin { get; set; } + public string AppVersion { get; set; } + public string Description { get; set; } + public Dictionary Fields { get; set; } + public string ConnectionString { get; set; } + + public Database() + { + + } + + public Database(DataRow dr) + { + Server = dr.Field("ServerName"); + DatabaseGuid = dr.Field("DatabaseGuid"); + DatabaseName = dr.Field("DatabaseName"); + PhysicalName = dr.Field("PhysicalName"); + OrgPin = dr.Field("OrgPin"); + AppVersion = dr.Field("AppVersion"); + Description = dr.Field("Description"); + Fields = new Dictionary(); + foreach (DataColumn column in dr.Table.Columns) + { + var index = dr.Table.Columns.IndexOf(column); + Fields.Add(column.ColumnName, dr[index].ToString()); + } + ConnectionString = BuildConnectionString(Server, PhysicalName); + } + + object ToDump() => (object)new + { + //Server, + //DatabaseGuid, + DatabaseName, + //PhysicalName, + //OrgPin, + //AppVersion, + //Description, + ConnectionString + }; +} + +#endregion + +#region *** Other methods here *** + +public void DoTheDumping() +{ + if (dumpOptions) + { + OptionsDump(); + } + if (dumpDBExclusions) + { + dbExclusions.Dump(nameof(dbExclusions)); + serverExclusions.Dump(nameof(serverExclusions)); + } + if (dumpDBTargets) + { + targetOrgPins.Dump(nameof(targetOrgPins)); + targetDBs.Dump(nameof(targetDBs)); + targetServers.Dump(nameof(targetServers)); + } + if (dumpAppVersionTargets) + { + appVersions.Dump(nameof(appVersions)); + } + if (dumpDBList) + { + databases.OrderBy(d => d.Server).ThenBy(d => d.PhysicalName).Dump($"{queryRegion} {nameof(databases)}"); + } + if (dumpAppVersions) + { + databases + .GroupBy(db => db.AppVersion, (grp, data) => data.Select(x => x.AppVersion).First()) + .OrderByDescending(db => db) + .Dump($"{queryRegion} {nameof(appVersions)}"); + } +} + +public static IOrderedEnumerable GetDatabases() +{ + switch (queryRegion) + { + case QueryRegions.Production: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc prod"; + break; + case QueryRegions.Training: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc training"; + break; + case QueryRegions.Oak: + smcServer = "ioak-sql-smc-01.sdt.local"; + smcDB = "smc qa"; + break; + default: + smcServer = "DDEN-SQL-SMC-01.sdt.local"; + smcDB = "smc dev"; + break; + } + if (dumpSmcSql) smcSql.Dump(nameof(smcSql)); + List databases = new List(); + var connStr = BuildConnectionString(smcServer, smcDB); + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(smcSql, conn); + command.CommandType = CommandType.Text; + var database = new DataSet(); + conn.Open(); + using (DbDataReader reader = command.ExecuteReader()) + { + while (true) + { + var table = new DataTable(); + database.Tables.Add(table); + table.Load(reader); + if (reader.IsClosed || !reader.NextResult()) break; + } + } + conn.Close(); + databases = database.Tables[0].AsEnumerable().Select(dr => new Database(dr)).ToList(); + databases = databases.Where(dr => !dbExclusions.Contains(dr.PhysicalName) && !serverExclusions.Contains(dr.Server)).ToList(); + if (targetOrgPins.Any()) + databases = databases.Where(dr => targetOrgPins.Contains(dr.OrgPin)).ToList(); + if (targetServers.Any()) + databases = databases.Where(dr => targetServers.Contains(dr.Server)).ToList(); + if (targetDBs.Any()) + databases = databases.Where(dr => targetDBs.Contains(dr.PhysicalName)).ToList(); + if (appVersions.Any()) + databases = databases.Where(dr => appVersions.Contains(dr.AppVersion)).ToList(); + } + return databases + .OrderBy(d => d.Server).ThenBy(d => d.PhysicalName); +} + +public static string BuildConnectionString(string server, string database, string username = null, string password = null) +{ + return username == null + ? $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;" + : $"data source={server};initial catalog='{database}';User ID={username};pwd={password}"; +} + +#endregion \ No newline at end of file diff --git a/CrossDBQuery AppVersions.linq b/CrossDBQuery AppVersions.linq new file mode 100644 index 0000000..05c6185 --- /dev/null +++ b/CrossDBQuery AppVersions.linq @@ -0,0 +1,382 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.Dynamic + System.IO.Compression + System.Threading.Tasks + + +#region *** Enumerations *** + +public enum QueryRegions +{ + Production, + Training, + Oak, + Dev +} + +#endregion + +#region *** Options *** + +public static string crossDBQueryPath = @"D:\CrossDBQueries"; +public static QueryRegions queryRegion = QueryRegions.Production; +public static bool dumpSmcSql = false; +public static bool dumpDBList = true; +public static bool dumpQueries = false; +public static string[] appVersions = { + +}; +public static string[] serverExclusions = { + @"paonsql19.sdt.local\instance1", + @"paonsql17.sdt.local\instance1", + @"p0555-sql-01.sdt.local\instance1", + "P0000-sql-01.sdt.local", + "P9900-SQL-03.sdt.local", + "P9900-sql-05.sdt.local" +}; +public static string[] targetServers = { +}; +public static string[] targetDBs = { + //"jazz prd Gillette Childrens 20150417.1" + //"jazz prd Southern Illinois 20140408.1" + //"jazz tst Southern Illinois 20190918.1" + //"jazz dev master Prod" +}; +#endregion *** Options *** + +#region *** SMC Settings and queries *** + +public static string smcSql => @"SELECT di.ServerName, di.DatabaseGUID, di.DatabaseName, di.PhysicalName, di.OrgPin, di.AppVersion, di.Description +FROM [dbo].[viewDatabaseInfo] di +WHERE 1=1" ++ (queryRegion == QueryRegions.Dev +? @" + AND di.PhysicalName like 'jazz%'" +: $@" + AND di.PhysicalName like 'jazz {(queryRegion != QueryRegions.Production ? "tst" : "prd")}%' + AND di.ServerName like 'p%'") ++ (serverExclusions.Any() +? $@" + AND di.ServerName not in ('{string.Join("', '", serverExclusions)}')" +: "") ++ (targetServers.Any() +? $@" + AND di.ServerName in ('{string.Join("', '", targetServers)}')" +: "") ++ (targetDBs.Any() +? $@" + AND di.PhysicalName IN ('{string.Join(", '", targetDBs)}') +" +: "") ++ (appVersions.Any() +? $@" + AND di.AppVersion in ('{string.Join("', '", appVersions)}')" +: ""); +public static string smcServer { get; set; } +public static string smcDB { get; set; } + +#endregion + +#region *** Program variables and settings *** + +public static int maxThreads = 8; +public static int timeoutInMinutes = 2; +public static IList crossDBQueryResults = new List(); +public static IOrderedEnumerable databases => GetDatabases(); + +#endregion + +void Main() +{ + databases + .GroupBy(db => db.AppVersion, (grp, data) => data.Select(x => x.AppVersion).First()) + .OrderByDescending(db => db) + .Dump("AppVersions"); + /* + databases + .Select(db => new + { + db.AppVersion, + db.PhysicalName, + OrgPin = $"'{db.OrgPin}'" }) + .Where(db => db.AppVersion != "2019.43") + .OrderByDescending(db => db.AppVersion) + .ThenBy(db => db.OrgPin) + .Dump("AppVersions"); + */ + + // ExecuteCrossDBQueries() +// //.Where(r => !r.Exceptions.Any() && (r.Results.First().Results.First().Count() != 2).Any()) +// .OrderBy(dbqr => dbqr.Results.Any() ? 0 : 1) +// .ThenBy(dbqr => dbqr.Database.DatabaseName).Dump(nameof(crossDBQueryResults)); +} + +#region *** Other classes *** + +public class CrossDBQueryResult +{ + public Database Database { get; set; } + public List Results { get; set; } + public List Exceptions { get; set; } + public CrossDBQueryResult() + { + Results = new List(); + Exceptions = new List(); + } + + public CrossDBQueryResult(Database database, string name, IEnumerable enumerable) + : this() + { + Database = database; + Results.Add(new SqlResults(name, enumerable)); + } + + public CrossDBQueryResult(Database database, Exception exception) + : this() + { + Database = database; + Exceptions.Add(exception.ExceptionMessage()); + } + + object ToDump() => Exceptions.Any() ? (object)new + { + Database, + Results, + Exceptions + } : new + { + Database, + Results + }; +} + +public class SqlResults +{ + public string Name { get; set; } + public IEnumerable Results { get; set; } + public SqlResults(string name, IEnumerable results) + { + Name = name; + Results = results; + } +} + +public static class ExceptionExtension +{ + public static string ExceptionMessage(this Exception exception) + { + return $@"{exception.Message}{(exception.InnerException != null + ? $@" + {"".PadLeft(40, '-')} + {exception.InnerException.ExceptionMessage()}" + : "")}"; + } +} + +public class Database +{ + public string Server { get; set; } + public Guid DatabaseGuid { get; set; } + public string DatabaseName { get; set; } + public string PhysicalName { get; set; } + public string OrgPin { get; set; } + public string AppVersion { get; set; } + public string Description { get; set; } + + public Database() + { + + } + + public Database(DataRow dr) + { + Server = dr.Field("ServerName"); + DatabaseGuid = dr.Field("DatabaseGuid"); + DatabaseName = dr.Field("DatabaseName"); + PhysicalName = dr.Field("PhysicalName"); + OrgPin = dr.Field("OrgPin"); + AppVersion = dr.Field("AppVersion"); + Description = dr.Field("Description"); + } +} + +public class ThreadWithState +{ + private string connectionString => BuildConnectionString(_server, _databaseName); + private Database _database; + private string _server => _database?.Server ?? string.Empty; + private string _databaseName => _database?.PhysicalName ?? string.Empty; + private string sqlName; + private IEnumerable _sqlQueries; + + public ThreadWithState(Database database, KeyValuePair> sqlqueries) + { + _database = database; + sqlName = sqlqueries.Key; + _sqlQueries = sqlqueries.Value; + } + + public void ThreadProc() + { + var crossDB = crossDBQueryResults.FirstOrDefault(x => x.Database == _database); + IEnumerable ThreadResults; + foreach (var sqlQuery in _sqlQueries) + { + try + { + ThreadResults = SelectDynamic(connectionString, sqlQuery); + var result = ThreadResults.First(); + if (crossDB != null) + { + crossDB.Results.Add(new SqlResults(sqlName, ThreadResults)); + } + else + { + crossDB = new CrossDBQueryResult(_database, sqlName, ThreadResults); + crossDBQueryResults.Add(crossDB); + } + } + catch (Exception ex) + { + if (crossDB != null) + { + crossDB.Exceptions.Add(new Exception(sqlQuery, ex).ExceptionMessage()); + } + else + { + crossDBQueryResults.Add(new CrossDBQueryResult(_database, new Exception(sqlQuery, ex))); + } + } + } + } +} + +#endregion + +#region *** Other methods here *** + +public static IOrderedEnumerable GetDatabases() +{ + switch (queryRegion) + { + case QueryRegions.Production: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc prod"; + break; + case QueryRegions.Training: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc training"; + break; + case QueryRegions.Oak: + smcServer = "ioak-sql-smc-01.sdt.local"; + smcDB = "smc qa"; + break; + default: + smcServer = "DDEN-SQL-SMC-01.sdt.local"; + smcDB = "smc dev"; + break; + } + if (dumpSmcSql) smcSql.Dump(nameof(smcSql)); + IEnumerable dbInfos = new List(); + var connStr = BuildConnectionString(smcServer, smcDB); + using (var conn = new SqlConnection(connStr)) + { + conn.Open(); + var command = new SqlCommand(smcSql, conn); + command.CommandType = CommandType.Text; + var table = new DataTable(); + using (SqlDataReader reader = command.ExecuteReader()) + { + table.BeginLoadData(); + table.Load(reader); + table.EndLoadData(); + conn.Close(); + } + dbInfos = table.AsEnumerable().Select(dr => new Database(dr)); + } + return dbInfos + .OrderBy(d => d.Server).ThenBy(d => d.PhysicalName); +} + +public Dictionary> GetUserQueries(string path = null) +{ + var grp = 0; + return Directory.GetFiles(path ?? Directory.GetCurrentDirectory(), "*.sql", SearchOption.TopDirectoryOnly) + .ToDictionary(d => Path.GetFileNameWithoutExtension(d), f => File.ReadAllLines(f) + .Select(r => + { + if (r.Equals("go", StringComparison.CurrentCultureIgnoreCase)) + { + r = ""; + return new { grp = grp++, r }; + } + else + { + return new { grp, r }; + } + }).GroupBy(r => r.grp, (x, lines) => string.Join(" ", lines.Select(l => l.r).Where(l => !string.IsNullOrEmpty(l))))); +} + +public static IEnumerable SelectDynamic(string connStr, string sql) +{ + using (var conn = new SqlConnection(connStr)) + { + conn.Open(); + var command = new SqlCommand(sql, conn); + command.CommandType = CommandType.Text; + command.CommandTimeout = (int)TimeSpan.FromMinutes(timeoutInMinutes).TotalSeconds; + using (var reader = command.ExecuteReader()) + { + var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList(); + foreach (IDataRecord record in reader as IEnumerable) + { + var expando = new ExpandoObject() as IDictionary; + foreach (var name in names) + expando[name] = record[name]; + + yield return expando; + } + } + conn.Close(); + } +} + +public IList ExecuteCrossDBQueries() +{ + if (dumpDBList) databases.Dump(nameof(databases)); + var queries = GetUserQueries(crossDBQueryPath); + if (dumpQueries) queries.Dump(nameof(queries)); + RunCrossDBQuery(databases, queries); + return crossDBQueryResults; +} + +public void RunCrossDBQuery(IEnumerable databases, Dictionary> sqlList) +{ + var stopWatch = DateTime.Now; + var query = databases.AsParallel() + .SelectMany(database => sqlList.Where(sql => sql.Value.Any()).AsParallel() + .Select(sql => new ThreadWithState(database, sql))); + foreach (var q in query) + { + q.ThreadProc(); + } + DateTime.Now.Subtract(stopWatch).TotalSeconds.Dump(nameof(stopWatch)); +} + +public static string BuildConnectionString(string server, string database, string username = null, string password = null) +{ + return username == null + ? $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;" + : $"data source={server};initial catalog='{database}';User ID={username};pwd={password}"; +} + +#endregion \ No newline at end of file diff --git a/CrossDBQuery with useParms.linq b/CrossDBQuery with useParms.linq new file mode 100644 index 0000000..e65ac37 --- /dev/null +++ b/CrossDBQuery with useParms.linq @@ -0,0 +1,484 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.Dynamic + System.IO.Compression + System.Threading.Tasks + System.Data.Common + + +#region *** Enumerations *** + +public enum QueryRegions +{ + Production, + Training, + Oak, + Dev +} + +#endregion + +#region *** Options *** + +public static QueryRegions queryRegion = QueryRegions.Production; +public static string crossDBQueryPath = @"D:\CrossDBQueries"; // This is the path to find the queries +public static bool dumpSmcSql = false; // This flag will dump the smc sql to the result +public static bool dumpDBList = false; // This flag will dump the databases to the result +public static bool dumpQueries = true; // This flag will dump the queries to the result +public static bool dumpDBExclusions = false; // This flag will dump the db and server exclusions +public static bool dumpDBTargets = false; // This flag will dump the db and server targets +public static bool dumpAppVersions = false; // This flag will dump the app versions used in the queryRegion +public static bool dumpAppVersionTargets = false; // This flag will dump the app versions targets +public static bool excludeExceptions = true; +public static bool queryCompress = false; +public static bool flatten = true; // This will flatten all of the results into a single list +public static bool showStopWatch = false; +public static bool noQueries = false; // This will stop the CrossDBQuery without running the queries +public static bool useParms = true; + +#endregion + +public static Parms parms = new Parms +{ + name = "FY2020" +}; + +#region *** Database Selection *** + +public static string[] appVersions = { // This is a list of appVersions to filter for in the database list + //"2019.42" +}; +public static string[] serverExclusions = { // This is a list of servers to exclude from the database list + @"paonsql19.sdt.local\instance1", + @"paonsql17.sdt.local\instance1", + @"p0555-sql-01.sdt.local\instance1", + "P0000-sql-01.sdt.local", + "P9900-SQL-03.sdt.local", + "P9900-sql-05.sdt.local" +}; +public static string[] dbExclusions = { // This is a list of database physical names to exclude from the database list +// "jazz tst Team AP Training 01", +// "jazz tst Team AP Training 02", +// "jazz tst Team AP Training 11", +// "jazz tst Team AP Training 12", +// "jazz tst Team AP Training 13", +// "jazz tst Team AP Training 14" +}; +public static string[] targetOrgPins = { // This is a list of org pins to target in the database list +}; +public static string[] targetServers = { // This is a list of servers to target in the database list +// "P9900-SQL-11.sdt.local" +}; +public static string[] targetDBs = { // This is a list of database physicial names to target in the database list +// "jazz prd Gillette Childrens 20150417.1" +// "jazz prd Southern Illinois 20140408.1" +// "jazz tst Southern Illinois 20190918.1" +// "jazz dev master Prod" +}; + +#endregion *** Options *** + +#region *** SMC Settings and queries *** + +public static string smcSql => @"SELECT di.ServerName, di.DatabaseGUID, di.DatabaseName, di.PhysicalName, di.OrgPin, di.AppVersion, di.Description +FROM [dbo].[viewDatabaseInfo] di +WHERE 1=1" ++ (queryRegion == QueryRegions.Dev +? @" + AND di.PhysicalName like 'jazz%'" +: $@" + AND di.PhysicalName like 'jazz {(queryRegion != QueryRegions.Production ? "tst" : "prd")}%' + AND di.ServerName like 'p%'"); +public static string smcServer { get; set; } +public static string smcDB { get; set; } + +#endregion + +#region *** Program variables and settings *** + +public static int maxThreads = 8; +public static int timeoutInMinutes = 2; +public static IList crossDBQueryResults = new List(); +public static IOrderedEnumerable databases => GetDatabases(); +public static Dictionary> queries = System.IO.Directory.Exists(crossDBQueryPath) + ? GetUserQueries(crossDBQueryPath) + : new Dictionary>(); + +#endregion + +void Main() +{ + if (dumpDBExclusions) + { + dbExclusions.Dump(nameof(dbExclusions)); + serverExclusions.Dump(nameof(serverExclusions)); + } + if (dumpDBTargets) + { + targetOrgPins.Dump(nameof(targetOrgPins)); + targetDBs.Dump(nameof(targetDBs)); + targetServers.Dump(nameof(targetServers)); + } + if (dumpAppVersionTargets) + { + appVersions.Dump(nameof(appVersions)); + } + if (dumpDBList) + { + databases.OrderBy(d => d.Server).ThenBy(d => d.PhysicalName).Dump($"{queryRegion} {nameof(databases)}"); + } + if (dumpAppVersions) + { + databases + .GroupBy(db => db.AppVersion, (grp, data) => data.Select(x => x.AppVersion).First()) + .OrderByDescending(db => db) + .Dump($"{queryRegion} {nameof(appVersions)}"); + } + if (noQueries) return; + var results = ExecuteCrossDBQueries() + //.Where(r => !r.Exceptions.Any() && (r.Results.First().Results.First().Count() != 2).Any()) + //.Where(r => !r.Exceptions.Any() && r.Results.First().Name.Contains("Variation")) + .OrderBy(dbqr => dbqr.Results.Any() ? 0 : 1) + .ThenBy(dbqr => dbqr.Database.DatabaseName); + if (flatten) + { + results + .SelectMany(dbqr => dbqr.Results.SelectMany(r => r.Results).ToList()) + .Dump(nameof(crossDBQueryResults)); + } + else + { + results.Dump(nameof(crossDBQueryResults)); + } +} + +public class Parms +{ + public string name { get; set; } +} + +#region *** Other classes *** + +public class CrossDBQueryResultLite +{ + public Database Database { get; set; } + public List Results { get; set; } +} +public class CrossDBQueryResult : CrossDBQueryResultLite +{ + public List Exceptions { get; set; } + public CrossDBQueryResult() + { + Results = new List(); + Exceptions = new List(); + } + + public CrossDBQueryResult(Database database, string name, IEnumerable enumerable) + : this() + { + Database = database; + Results.Add(new SqlResults(name, enumerable)); + } + + public CrossDBQueryResult(Database database, Exception exception) + : this() + { + Database = database; + Exceptions.Add(exception.ExceptionMessage()); + } + + object ToDump() => excludeExceptions + ? (object)new + { + Database, + Results + } +: new +{ + Database, + Results, + Exceptions +}; +} + +public class SqlResults +{ + public string Name { get; set; } + public IEnumerable Results { get; set; } + public SqlResults(string name, IEnumerable results) + { + Name = name; + Results = results; + } +} + +public static class ExceptionExtension +{ + public static string ExceptionMessage(this Exception exception) + { + return $@"{exception.Message}{(exception.InnerException != null + ? $@" + {"".PadLeft(40, '-')} + {exception.InnerException.ExceptionMessage()}" + : "")}"; + } +} + +public class Database +{ + public string Server { get; set; } + public Guid DatabaseGuid { get; set; } + public string DatabaseName { get; set; } + public string PhysicalName { get; set; } + public string OrgPin { get; set; } + public string AppVersion { get; set; } + public string Description { get; set; } + public Dictionary Fields { get; set; } + + public Database() + { + + } + + public Database(DataRow dr) + { + Server = dr.Field("ServerName"); + DatabaseGuid = dr.Field("DatabaseGuid"); + DatabaseName = dr.Field("DatabaseName"); + PhysicalName = dr.Field("PhysicalName"); + OrgPin = dr.Field("OrgPin"); + AppVersion = dr.Field("AppVersion"); + Description = dr.Field("Description"); + Fields = new Dictionary(); + foreach (DataColumn column in dr.Table.Columns) + { + var index = dr.Table.Columns.IndexOf(column); + Fields.Add(column.ColumnName, dr[index].ToString()); + } + } + + object ToDump() => (object)new + { + Server, + DatabaseGuid, + DatabaseName, + PhysicalName, + OrgPin, + AppVersion, + Description + }; +} + +public class ThreadWithState +{ + private string connectionString => BuildConnectionString(_server, _databaseName); + private Database _database; + private string _server => _database?.Server ?? string.Empty; + private string _databaseName => _database?.PhysicalName ?? string.Empty; + private string sqlName; + private IEnumerable _sqlQueries; + + public ThreadWithState(Database database, KeyValuePair> sqlqueries) + { + _database = database; + sqlName = sqlqueries.Key; + _sqlQueries = sqlqueries.Value; + } + + public void ThreadProc() + { + var crossDB = crossDBQueryResults.FirstOrDefault(x => x.Database == _database); + IEnumerable ThreadResults; + foreach (var sqlQuery in _sqlQueries) + { + try + { + ThreadResults = SelectDynamic(_database, connectionString, sqlQuery); + var result = ThreadResults.First(); + if (crossDB != null) + { + crossDB.Results.Add(new SqlResults(sqlName, ThreadResults)); + } + else + { + crossDB = new CrossDBQueryResult(_database, sqlName, ThreadResults); + crossDBQueryResults.Add(crossDB); + } + } + catch (Exception ex) + { + if (crossDB != null) + { + crossDB.Exceptions.Add(new Exception(sqlQuery, ex).ExceptionMessage()); + } + else + { + crossDBQueryResults.Add(new CrossDBQueryResult(_database, new Exception(sqlQuery, ex))); + } + } + } + } +} + +#endregion + +#region *** Other methods here *** + +public static IOrderedEnumerable GetDatabases() +{ + switch (queryRegion) + { + case QueryRegions.Production: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc prod"; + break; + case QueryRegions.Training: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc training"; + break; + case QueryRegions.Oak: + smcServer = "ioak-sql-smc-01.sdt.local"; + smcDB = "smc qa"; + break; + default: + smcServer = "DDEN-SQL-SMC-01.sdt.local"; + smcDB = "smc dev"; + break; + } + if (dumpSmcSql) smcSql.Dump(nameof(smcSql)); + List databases = new List(); + var connStr = BuildConnectionString(smcServer, smcDB); + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(smcSql, conn); + command.CommandType = CommandType.Text; + var database = new DataSet(); + conn.Open(); + using (DbDataReader reader = command.ExecuteReader()) + { + while (true) + { + var table = new DataTable(); + database.Tables.Add(table); + table.Load(reader); + if (reader.IsClosed || !reader.NextResult()) break; + } + } + conn.Close(); + databases = database.Tables[0].AsEnumerable().Select(dr => new Database(dr)).ToList(); + databases = databases.Where(dr => !dbExclusions.Contains(dr.PhysicalName) && !serverExclusions.Contains(dr.Server)).ToList(); + if (targetOrgPins.Any()) + databases = databases.Where(dr => targetOrgPins.Contains(dr.OrgPin)).ToList(); + if (targetServers.Any()) + databases = databases.Where(dr => targetServers.Contains(dr.Server)).ToList(); + if (targetDBs.Any()) + databases = databases.Where(dr => targetDBs.Contains(dr.PhysicalName)).ToList(); + if (appVersions.Any()) + databases = databases.Where(dr => appVersions.Contains(dr.AppVersion)).ToList(); + } + return databases + .OrderBy(d => d.Server).ThenBy(d => d.PhysicalName); +} + +public static Dictionary> GetUserQueries(string path = null) +{ + var grp = 0; + var queries = Directory.GetFiles(path ?? Directory.GetCurrentDirectory(), "*.sql", SearchOption.TopDirectoryOnly) + .ToDictionary(d => Path.GetFileNameWithoutExtension(d), f => File.ReadAllLines(f) + .Select(r => + { + if (r.Equals("go", StringComparison.CurrentCultureIgnoreCase)) + { + r = ""; + return new { grp = grp++, r }; + } + else + { + return new { grp, r }; + } + }).GroupBy(r => r.grp, (x, lines) => string.Join(queryCompress ? " " : "\r\n", lines.Select(l => l.r).Where(l => !string.IsNullOrEmpty(l))))); + + // foreach (var key in queries.Keys) + // { + // foreach (var query in queries[key]) + // { + // if (useParms) + // { + // FormattableString formatter = $""; + // string.Format(formatter, parms).Dump(); + // } + // } + // } + + if (dumpQueries) + queries.Dump(nameof(queries)); + return queries; +} + +public static IEnumerable SelectDynamic(Database db, string connStr, string sql) +{ + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(sql, conn); + command.CommandType = CommandType.Text; + command.CommandTimeout = (int)TimeSpan.FromMinutes(timeoutInMinutes).TotalSeconds; + var database = new DataSet(); + conn.Open(); + using (DbDataReader reader = command.ExecuteReader()) + { + while (true) + { + var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList(); + foreach (IDataRecord record in reader as IEnumerable) + { + var expando = new ExpandoObject() as IDictionary; + if (flatten) + db.Fields.ForEach((x, y) => expando[x.Key] = x.Value); + foreach (var name in names) + expando[name] = record[name]; + + yield return expando; + } + if (reader.IsClosed || !reader.NextResult()) break; + } + } + conn.Close(); + } +} + +public IList ExecuteCrossDBQueries() +{ + RunCrossDBQuery(databases, queries); + return crossDBQueryResults; +} + +public void RunCrossDBQuery(IEnumerable databases, Dictionary> sqlList) +{ + var stopWatch = DateTime.Now; + var query = databases.AsParallel() + .SelectMany(database => sqlList.Where(sql => sql.Value.Any()).AsParallel() + .Select(sql => new ThreadWithState(database, sql))); + foreach (var q in query) + { + q.ThreadProc(); + } + var timer = DateTime.Now.Subtract(stopWatch).TotalSeconds; + if (showStopWatch) timer.Dump(nameof(stopWatch)); +} + +public static string BuildConnectionString(string server, string database, string username = null, string password = null) +{ + return username == null + ? $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;" + : $"data source={server};initial catalog='{database}';User ID={username};pwd={password}"; +} + +#endregion \ No newline at end of file diff --git a/CrossDBQuery.linq b/CrossDBQuery.linq new file mode 100644 index 0000000..567d2fc --- /dev/null +++ b/CrossDBQuery.linq @@ -0,0 +1,503 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.Dynamic + System.IO.Compression + System.Threading.Tasks + System.Data.Common + + +#region *** Enumerations *** + +public enum QueryRegions +{ + Production, + Training, + Oak, + Dev +} + +#endregion + +#region *** Options *** + +public static QueryRegions queryRegion = QueryRegions.Dev; +public static string crossDBQueryPath = @"C:\Users\tlamb\Documents\CrossDBQueries"; // This is the path to find the queries +public static bool checkForCILicensing = true; // This flag will add a column if the client db is licensed for CI +public static bool dumpOptions = false; // This flag will dumpt this set of options +public static bool dumpSmcSql = false; // This flag will dump the smc sql to the result +public static bool dumpDBList = false; // This flag will dump the databases to the result +public static bool dumpQueries = false; // This flag will dump the queries to the result +public static bool dumpDBExclusions = false; // This flag will dump the db and server exclusions +public static bool dumpDBTargets = false; // This flag will dump the db and server targets +public static bool dumpAppVersions = false; // This flag will dump the app versions used in the queryRegion +public static bool dumpAppVersionTargets = false; // This flag will dump the app versions targets +public static bool excludeExceptions = true; +public static bool queryCompress = false; +public static bool flatten = true; // This will flatten all of the results into a single list +public static bool showStopWatch = false; +public static bool noQueries = false; // This will stop the CrossDBQuery without running the queries + +#endregion + +public static Parms parms = new Parms +{ + name = "FY2020" +}; + +#region *** Database Selection *** + +public static string[] appVersions = { // This is a list of appVersions to filter for in the database list + //"2020.31" +}; +public static string[] serverExclusions = { // This is a list of servers to exclude from the database list + @"paonsql19.sdt.local\instance1", + @"paonsql17.sdt.local\instance1", + @"p0555-sql-01.sdt.local\instance1", + "P0000-sql-01.sdt.local", + "P9900-SQL-03.sdt.local", + "P9900-sql-05.sdt.local" +}; +public static string[] dbExclusions = { // This is a list of database physical names to exclude from the database list +}; +public static string[] targetOrgPins = { // This is a list of org pins to target in the database list +// "0430", "0434", "0555", "0777" +}; +public static string[] targetServers = { // This is a list of servers to target in the database list +// "P9900-SQL-11.sdt.local" +// "D0018-SQL-01.sdt.local" +}; +public static string[] targetDBs = { // This is a list of database physicial names to target in the database list +// "jazz prd Gillette Childrens 20150417.1" +// "jazz prd Southern Illinois 20140408.1" +// "jazz tst Southern Illinois 20190918.1" +// "jazz dev master Prod" +}; + +#endregion *** Options *** + +#region *** SMC Settings and queries *** + +public static string smcSql => $@"SELECT di.ServerName, di.DatabaseGUID, di.DatabaseName, di.PhysicalName, di.OrgPin, di.AppVersion, di.Description +{(checkForCILicensing ? " ,(select COUNT(*) from [dbo].[viewLicenseLink] l where l.NAME = 'ContinuousImprovement' and l.DatabaseGUID = di.DatabaseGUID and l.IsLicensed = 1) CI_LICENSED" : "")} +FROM [dbo].[viewDatabaseInfo] di +WHERE 1=1" ++ (queryRegion == QueryRegions.Dev +? @" + AND di.PhysicalName like 'jazz%'" +: $@" + AND di.PhysicalName like 'jazz {(queryRegion != QueryRegions.Production ? "tst" : "prd")}%' + AND di.ServerName like 'p%'"); +public static string smcServer { get; set; } +public static string smcDB { get; set; } + +#endregion + +#region *** Program variables and settings *** + +public static int maxThreads = 8; +public static int timeoutInMinutes = 2; +public static IList crossDBQueryResults = new List(); +public static IOrderedEnumerable databases => GetDatabases(); +public static Dictionary> queries = System.IO.Directory.Exists(crossDBQueryPath) + ? GetUserQueries(crossDBQueryPath) + : new Dictionary>(); + +#endregion + +void Main() +{ + if (dumpOptions) + { + OptionsDump(); + } + if (dumpDBExclusions) + { + dbExclusions.Dump(nameof(dbExclusions)); + serverExclusions.Dump(nameof(serverExclusions)); + } + if (dumpDBTargets) + { + targetOrgPins.Dump(nameof(targetOrgPins)); + targetDBs.Dump(nameof(targetDBs)); + targetServers.Dump(nameof(targetServers)); + } + if (dumpAppVersionTargets) + { + appVersions.Dump(nameof(appVersions)); + } + if (dumpDBList) + { + databases.OrderBy(d => d.Server).ThenBy(d => d.PhysicalName).Dump($"{queryRegion} {nameof(databases)}"); + } + if (dumpAppVersions) + { + databases + .GroupBy(db => db.AppVersion, (grp, data) => data.Select(x => x.AppVersion).First()) + .OrderByDescending(db => db) + .Dump($"{queryRegion} {nameof(appVersions)}"); + } + if (noQueries) return; + var results = ExecuteCrossDBQueries() + .OrderBy(dbqr => dbqr.Results.Any() ? 0 : 1) + .ThenBy(dbqr => dbqr.Database.DatabaseName); + if (flatten) + { + results + .SelectMany(dbqr => dbqr.Results.SelectMany(r => r.Results).ToList()) + .Where(dbqr => dbqr.CI_LICENSED == "1") + .GroupBy(dbqr => dbqr.DatabaseGUID, (g,d) => d.First()) + .Distinct() + .Dump(nameof(crossDBQueryResults)); + } + else + { + results.Dump(nameof(crossDBQueryResults)); + } +} + +public void OptionsDump() +{ + var options = new + { + queryRegion, + crossDBQueryPath, + dumpOptions, + dumpSmcSql, + dumpDBList, + dumpQueries, + dumpDBExclusions, + dumpDBTargets, + dumpAppVersions, + dumpAppVersionTargets, + excludeExceptions, + queryCompress, + flatten, + showStopWatch, + noQueries + }; + options.Dump(nameof(options)); +} + +public class Parms +{ + public string name { get; set; } +} + +#region *** Other classes *** + +public class CrossDBQueryResultLite +{ + public Database Database { get; set; } + public List Results { get; set; } +} +public class CrossDBQueryResult : CrossDBQueryResultLite +{ + public List Exceptions { get; set; } + public CrossDBQueryResult() + { + Results = new List(); + Exceptions = new List(); + } + + public CrossDBQueryResult(Database database, string name, IEnumerable enumerable) + : this() + { + Database = database; + Results.Add(new SqlResults(name, enumerable)); + } + + public CrossDBQueryResult(Database database, Exception exception) + : this() + { + Database = database; + Exceptions.Add(exception.ExceptionMessage()); + } + + object ToDump() => excludeExceptions + ? (object)new + { + Database, + Results + } +: new +{ + Database, + Results, + Exceptions +}; +} + +public class SqlResults +{ + public string Name { get; set; } + public IEnumerable Results { get; set; } + public SqlResults(string name, IEnumerable results) + { + Name = name; + Results = results; + } +} + +public static class ExceptionExtension +{ + public static string ExceptionMessage(this Exception exception) + { + return $@"{exception.Message}{(exception.InnerException != null + ? $@" + {"".PadLeft(40, '-')} + {exception.InnerException.ExceptionMessage()}" + : "")}"; + } +} + +public class Database +{ + public string Server { get; set; } + public Guid DatabaseGuid { get; set; } + public string DatabaseName { get; set; } + public string PhysicalName { get; set; } + public string OrgPin { get; set; } + public string AppVersion { get; set; } + public string Description { get; set; } + public Dictionary Fields { get; set; } + + public Database() + { + + } + + public Database(DataRow dr) + { + Server = dr.Field("ServerName"); + DatabaseGuid = dr.Field("DatabaseGuid"); + DatabaseName = dr.Field("DatabaseName"); + PhysicalName = dr.Field("PhysicalName"); + OrgPin = dr.Field("OrgPin"); + AppVersion = dr.Field("AppVersion"); + Description = dr.Field("Description"); + Fields = new Dictionary(); + foreach (DataColumn column in dr.Table.Columns) + { + var index = dr.Table.Columns.IndexOf(column); + Fields.Add(column.ColumnName, dr[index].ToString()); + } + } + + object ToDump() => (object)new + { + Server, + DatabaseGuid, + DatabaseName, + PhysicalName, + OrgPin, + AppVersion, + Description + }; +} + +public class ThreadWithState +{ + private string connectionString => BuildConnectionString(_server, _databaseName); + private Database _database; + private string _server => _database?.Server ?? string.Empty; + private string _databaseName => _database?.PhysicalName ?? string.Empty; + private string sqlName; + private IEnumerable _sqlQueries; + + public ThreadWithState(Database database, KeyValuePair> sqlqueries) + { + _database = database; + sqlName = sqlqueries.Key; + _sqlQueries = sqlqueries.Value; + } + + public void ThreadProc() + { + var crossDB = crossDBQueryResults.FirstOrDefault(x => x.Database == _database); + IEnumerable ThreadResults; + foreach (var sqlQuery in _sqlQueries) + { + try + { + ThreadResults = SelectDynamic(_database, connectionString, sqlQuery); + var result = ThreadResults.First(); + if (crossDB != null) + { + crossDB.Results.Add(new SqlResults(sqlName, ThreadResults)); + } + else + { + crossDB = new CrossDBQueryResult(_database, sqlName, ThreadResults); + crossDBQueryResults.Add(crossDB); + } + } + catch (Exception ex) + { + if (crossDB != null) + { + crossDB.Exceptions.Add(new Exception(sqlQuery, ex).ExceptionMessage()); + } + else + { + crossDBQueryResults.Add(new CrossDBQueryResult(_database, new Exception(sqlQuery, ex))); + } + } + } + } +} + +#endregion + +#region *** Other methods here *** + +public static IOrderedEnumerable GetDatabases() +{ + switch (queryRegion) + { + case QueryRegions.Production: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc prod"; + break; + case QueryRegions.Training: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc training"; + break; + case QueryRegions.Oak: + smcServer = "ioak-sql-smc-01.sdt.local"; + smcDB = "smc qa"; + break; + default: + smcServer = "DDEN-SQL-SMC-01.sdt.local"; + smcDB = "smc dev"; + break; + } + if (dumpSmcSql) smcSql.Dump(nameof(smcSql)); + List databases = new List(); + var connStr = BuildConnectionString(smcServer, smcDB); + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(smcSql, conn); + command.CommandType = CommandType.Text; + var database = new DataSet(); + conn.Open(); + using (DbDataReader reader = command.ExecuteReader()) + { + while (true) + { + var table = new DataTable(); + database.Tables.Add(table); + table.Load(reader); + if (reader.IsClosed || !reader.NextResult()) break; + } + } + conn.Close(); + databases = database.Tables[0].AsEnumerable().Select(dr => new Database(dr)).ToList(); + databases = databases.Where(dr => !dbExclusions.Contains(dr.PhysicalName) && !serverExclusions.Contains(dr.Server)).ToList(); + if (targetOrgPins.Any()) + databases = databases.Where(dr => targetOrgPins.Contains(dr.OrgPin)).ToList(); + if (targetServers.Any()) + databases = databases.Where(dr => targetServers.Contains(dr.Server)).ToList(); + if (targetDBs.Any()) + databases = databases.Where(dr => targetDBs.Contains(dr.PhysicalName)).ToList(); + if (appVersions.Any()) + databases = databases.Where(dr => appVersions.Contains(dr.AppVersion)).ToList(); + } + return databases + .OrderBy(d => d.Server).ThenBy(d => d.PhysicalName); +} + +public static Dictionary> GetUserQueries(string path = null) +{ + var grp = 0; + var queries = Directory.GetFiles(path ?? Directory.GetCurrentDirectory(), "*.sql", SearchOption.TopDirectoryOnly) + .ToDictionary(d => Path.GetFileNameWithoutExtension(d), f => File.ReadAllLines(f) + .Select(r => + { + if (r.Equals("go", StringComparison.CurrentCultureIgnoreCase)) + { + r = ""; + return new { grp = grp++, r }; + } + else + { + return new { grp, r }; + } + }).GroupBy(r => r.grp, (x, lines) => string.Join(queryCompress ? " " : "\r\n", lines.Select(l => l.r).Where(l => !string.IsNullOrEmpty(l))))); + + if (dumpQueries) + queries.Dump(nameof(queries)); + return queries; +} + +public static IEnumerable SelectDynamic(Database db, string connStr, string sql) +{ + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(sql, conn); + command.CommandType = CommandType.Text; + command.CommandTimeout = (int)TimeSpan.FromMinutes(timeoutInMinutes).TotalSeconds; + var database = new DataSet(); + conn.Open(); + using (DbDataReader reader = command.ExecuteReader()) + { + while (true) + { + var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList(); + foreach (IDataRecord record in reader as IEnumerable) + { + var expando = new ExpandoObject() as IDictionary; + if (flatten) + { + foreach (var field in db.Fields) + { + expando[field.Key] = field.Value; + } + } + foreach (var name in names) + expando[name] = record[name]; + + yield return expando; + } + if (reader.IsClosed || !reader.NextResult()) break; + } + } + conn.Close(); + } +} + +public IList ExecuteCrossDBQueries() +{ + RunCrossDBQuery(databases, queries); + return crossDBQueryResults; +} + +public void RunCrossDBQuery(IEnumerable databases, Dictionary> sqlList) +{ + var stopWatch = DateTime.Now; + var query = databases.AsParallel() + .SelectMany(database => sqlList.Where(sql => sql.Value.Any()).AsParallel() + .Select(sql => new ThreadWithState(database, sql))); + foreach (var q in query) + { + q.ThreadProc(); + } + var timer = DateTime.Now.Subtract(stopWatch).TotalSeconds; + if (showStopWatch) timer.Dump(nameof(stopWatch)); +} + +public static string BuildConnectionString(string server, string database, string username = null, string password = null) +{ + return username == null + ? $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;" + : $"data source={server};initial catalog='{database}';User ID={username};pwd={password}"; +} + +#endregion \ No newline at end of file diff --git a/CultureInfo with examples.linq b/CultureInfo with examples.linq new file mode 100644 index 0000000..b684de2 --- /dev/null +++ b/CultureInfo with examples.linq @@ -0,0 +1,205 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + <RuntimeDirectory>\System.ComponentModel.Composition.dll + <RuntimeDirectory>\System.ComponentModel.dll + <RuntimeDirectory>\System.Net.dll + <RuntimeDirectory>\System.Net.Http.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + TimeZoneNames + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.Globalization + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + TimeZoneNames + + +void Main() +{ + var currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture; + // Get server DateTime. + DateTime date = DateTime.Now; + var amount = 12345.67M; + + // Get a list of all Cultures + List cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures) + //.Where(ci => ci.Name == "en-MW") + .ToList(); + + // Add the Cultures to an ArrayList so we can sort them Alphabetically by name. + List cultureList = new List(); + foreach (CultureInfo culture in cultures) + { + System.Threading.Thread.CurrentThread.CurrentCulture = culture; + RegionInfo regionInfo = default(RegionInfo); + if (culture.LCID != 4096 && !culture.Equals(CultureInfo.InvariantCulture)) + { + regionInfo = new RegionInfo(culture.LCID); + } + string pattern = null; + switch (culture.NumberFormat.CurrencyPositivePattern) + { + case 0: + pattern = "{0}{1:N" + culture.NumberFormat.CurrencyDecimalDigits + "}"; + break; + case 1: + pattern = "{1:N" + culture.NumberFormat.CurrencyDecimalDigits + "}{0}"; + break; + case 2: + pattern = "{0} {1:N" + culture.NumberFormat.CurrencyDecimalDigits + "}"; + break; + case 3: + pattern = "{1:N" + culture.NumberFormat.CurrencyDecimalDigits + "} {0}"; + break; + } + cultureList.Add(new CultureData + { + EnglishName = culture.EnglishName, + Name = culture.Name, + Details = new CultureDetails + { + ShortDate_Format = culture.DateTimeFormat.ShortDatePattern, + ShortDate_Example = date.ToShortDateString(), + LongDate_Format = culture.DateTimeFormat.LongDatePattern, + LongDate_Example = date.ToLongDateString(), + ShortTime_Format = culture.DateTimeFormat.ShortTimePattern, + ShortTime_Example = date.ToShortTimeString(), + LongTime_Format = culture.DateTimeFormat.LongTimePattern, + LongTime_Example = date.ToLongTimeString(), + Currency_EnglishName = regionInfo?.CurrencyEnglishName ?? string.Empty, + Currency_NativeName = regionInfo?.CurrencyNativeName ?? string.Empty, + Currency_Format = pattern, + Currency_Example = string.Format(culture, "{0:C}", amount), + Currency_ExampleNeg = string.Format(culture, "{0:C}", (amount * -1)), + Currency_ExampleAlt = string.Format(culture, "{0:c}", amount), + Currency_ExampleAltNeg = string.Format(culture, "{0:C}", (amount * -1)), + Percentage_Format = $"{{{culture.NumberFormat.PercentPositivePattern}{culture.NumberFormat.PercentDecimalSeparator}{culture.NumberFormat.PercentDecimalDigits}:P}}", + Percentage_Symbol = culture.NumberFormat.PercentSymbol, + Percentage_Example = string.Format(culture, "{0:P}", .333) + }, + MonthNames = MonthNames(culture), +// TimeZones = TimeZones(currentCulture) + }); + } + + // Sort Cultures + //cultureList.Sort(new StringComparer()); + cultureList + //.Where(l => l.Details.Percentage_Symbol != "%") + .OrderBy(c => c.EnglishName) + //.Where(c => c.EnglishName.Contains("Bermuda")) + .Dump(nameof(cultureList)); + + currentCulture = CultureInfo.GetCultures(CultureTypes.SpecificCultures).FirstOrDefault(c => c.EnglishName == "English (United States)"); + System.Threading.Thread.CurrentThread.CurrentCulture = currentCulture; + +} + +class CultureDetails +{ + public string ShortDate_Format { get; set; } + public string ShortDate_Example { get; set; } + public string LongDate_Format { get; set; } + public string LongDate_Example { get; set; } + public string ShortTime_Format { get; set; } + public string ShortTime_Example { get; set; } + public string LongTime_Format { get; set; } + public string LongTime_Example { get; set; } + public string Currency_EnglishName { get; set; } + public string Currency_NativeName { get; set; } + public string Currency_Format { get; set; } + public string Currency_Example { get; set; } + public string Currency_ExampleNeg { get; set; } + public string Currency_ExampleAlt { get; set; } + public string Currency_ExampleAltNeg { get; set; } + public string Percentage_Format { get; set; } + public string Percentage_Symbol { get; set; } + public string Percentage_Example { get; set; } +} +class CultureData +{ + public string EnglishName { get; set; } + public string Name { get; set; } + public IDictionary MonthNames { get; set; } + public CultureDetails Details { get; set; } + public IEnumerable TimeZones { get; set; } +} + +public IDictionary MonthNames(CultureInfo culture) +{ + return Enumerable.Range(1, 12).ToList() + .Select(mm => new { Key = mm, Value = culture.DateTimeFormat.GetMonthName(mm) }) + .ToDictionary(item => item.Key, item => item.Value); +} + +public IEnumerable TimeZones(CultureInfo culture) +{ + return TimeZoneInfo.GetSystemTimeZones(); +} + +public void TimeZoneList(CultureInfo culture) +{ + TimeZoneInfo.GetSystemTimeZones() + .SelectMany(tzi => new[] { + TZNames.GetAbbreviationsForTimeZone(tzi.Id, culture.Name).Daylight != TZNames.GetAbbreviationsForTimeZone(tzi.Id, culture.Name).Standard + ? new { Key = tzi.Id.Replace("Standard", "Daylight"), Value = TZNames.GetAbbreviationsForTimeZone(tzi.Id, culture.Name).Daylight } + : new { Key = tzi.Id, Value = TZNames.GetAbbreviationsForTimeZone(tzi.Id, culture.Name).Daylight }, + new { Key = tzi.Id, Value = TZNames.GetAbbreviationsForTimeZone(tzi.Id, culture.Name).Standard }}) + .GroupBy(x => x.Key) + .Select(g => g.First()) + .ToDictionary(item => item.Key, item => item.Value) + .OrderBy(item => item.Key) + .Dump(); +} \ No newline at end of file diff --git a/DB Query Exceptions.linq b/DB Query Exceptions.linq new file mode 100644 index 0000000..68ee169 --- /dev/null +++ b/DB Query Exceptions.linq @@ -0,0 +1,605 @@ + + + 580b3b8d-cc02-4a68-8fbd-d1ec374a25f2 + true + D0001-sql-11.sdt.local + jazz dev master Prod + true + + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Linq.Dynamic + + +// This link provides a good explanation of the Dynamic Query used in the DataTableJoins +// https://ecs.syr.edu/faculty/fawcett/handouts/CoreTechnologies/CSharp/samples/CSharpSamples/LinqSamples/DynamicQuery/Dynamic%20Expressions.html +// +#region Options + +public static int TopRows = 1000; //int.MaxValue; +public static int TableDumpDepth = int.MaxValue; //2; +public static bool ShowTableQuery = false; +public static bool ShowTablesToRemove = false; +public static bool ShowTableNames = false; +public static bool ShowTableList = false; +public static bool ShowMissingUpdate = true; +public static bool ShowMissingLegacy = false; + +#endregion + +private Connections connections = new Connections +{ + //Legacy = new ServerInstance("E0001-SQL-11.sdt.local", "StrataSphere"), + //Update = new ServerInstance("D0011-SQL-01.sdt.local", "StrataSphere") + Legacy = new ServerInstance("D0011-SQL-01.sdt.local", "jazz tst Southern Illinois 20190918.1"), + Update = new ServerInstance("D0011-SQL-01.sdt.local", "jazz tst Southern Illinois 20200331.1") + //Legacy = new ServerInstance("D0001-SQL-11.sdt.local", "jazz tst master prod 20190708.1"), + //Update = new ServerInstance("D0001-SQL-11.sdt.local", "jazz tst master prod") +}; +// Hints: +// 1) if you pass a null for the table list it will include all tables in the schema +// 2) if you pass a table name like "C%"' it will only include all tables that start with C +private List SchemasAndTablesToReview = new List { + new TablesAndColumns("cci", new[] {"%QVILineItemOpportunity%"}), + //new TablesAndColumns("clientdss", new [] { "FactPatientEncounterSummary" }), + //new TablesAndColumns("dss", new [] {"%CaseType%"}, new[] {"CaseTypeDRGMapping","CaseTypeFamilyMapping","FactCaseTypeMapping"}), + //new TablesAndColumns("fw", new []{ "DimAgeCohort"}) +}; + +void Main() +{ + var tables = GetTables().ToList(); + // Using 'D|' at the beginning of a column name implies that the sort order is descending for that column + tables.ForEach(table => + { + switch (table.SchemaName) + { + case "cci": + switch (table.TableName) + { + case "ChargeCodeConfig": + table.Init( + new[] { "ChargeCodeID", "CostDriver" }, + keyColumns: new[] { "ChargeCodeID", "CostDriver" } + ); + break; + case "ChargeCodeCostDetail": + table.Init( + new[] { "EntityID", "ChargeCodeID" }, + keyColumns: new[] { "EntityID", "ChargeCodeID" } + ); + break; + case "Configuration": + table.Init(new[] { "D|FiscalYearID" }, new[] { "InitiativeIsSimplifiedWorkflow" }, new[] { "FiscalYearId" }); + break; + case "InitiativeWorkflowHistory": + table.Init(new[] { "FromStep", "ToStep" }); + break; + case "VariationEncounterSavingInfo": + table.Init(new[] { "EncounterRecordNumber" }); + break; + case "FactOpportunityMetric": + table.Init(new[] { "FiscalYearID", "FiscalMonthID" }); + break; + case "FactOpportunitySavings": + table.Init(new[] { "FiscalyYearID", "FiscalMonthID" }); + break; + case "Initiative": + table.Init(new[] { "Name" }); + break; + case "SystemSetting": + table.Excludes(new[] { "IsEncrypted" }); + break; + case "QVILineItemOpportunity": + table.KeyColumns(new[] {"BreakdownID", "QVILineItemID", "QualityVariationEventID"}); + break; + case "VariationOpportunity": + table.Init( + new[] { "CaseTypeEntityId", "CostDriver" }, + keyColumns: new[] { "CostDriver", "CastTypeEntityId" } + ); + break; + }; + break; + case "clientdss": + switch (table.TableName) + { + case "FactPatientEncounterSummary": + table.Init( + new[] { "EncounterRecordNumber" }, + new[] { "MikeQAtest1ID", "CustomJesseValidatingAllOthers", "CustomNewCalculatedSystemFieldasdf" }, + where: "OBJ.MSDRGCaseTypeFamilyID <> 0 OR OBJ.APRDRGCaseTypeFamilyID <> 0"); + break; + }; + break; + case "dss": + switch (table.TableName) + { + case "CaseTypeDRGMapping": + table.Init(new[] { "DRGID" }, keyColumns: new[] { "DRGID" }); + break; + case "CaseTypeEntity": + table.Init(new[] { "EntityID", "CaseTypeEntityID" }, + keyColumns: new[] { "EntityID", "CaseTypeEntityID" }); + break; + case "CaseTypeFamily": + table.Init(new[] { "Name", "CaseTypeFamilyGlobalID", "CaseTypeFamilyID" }, + keyColumns: new[] { "Name", "CaseTypeFamilyGlobalID" }); + break; + case "CaseTypeFamilyMappingAPRDRG": + table.Init(new[] { "APRDRGCode", "CaseTypeFamilyVersionID", "CaseTypeFamilyID" }, + keyColumns: new[] { "APRDRGCode", "CaseTypeFamilyVersionID", "CaseTypeFamilyID" }); + break; + case "CaseTypeFamilyMappingCPT": + table.Init(new[] { "CPTCode", "CaseTypeFamilyVersionID", "CaseTypeFamilyID" }, + keyColumns: new[] { "CPTCode", "CaseTypeFamilyVersionID", "CaseTypeFamilyID" }); + break; + case "CaseTypeFamilyMappingICD10": + table.Init(new[] { "ICD10Code", "MSDRGCode", "CaseTypeFamilyVersionID", "CaseTypeFamilyID" }, + keyColumns: new[] { "ICD10Code", "MSDRGCode", "CaseTypeFamilyVersionID", "CaseTypeFamilyID" }); + break; + case "CaseTypeFamilyVersion": + table.Init(new[] { "CaseTypeFamilyVersionID" }, + keyColumns: new[] { "CaseTypeFamilyVersionID" }); + break; + case "DimCaseType": + table.Init(new[] { "CaseTypeFamilyID", "CaseTypeId", "Name" }, jsonColumns: new[] { "CaseTypeConfigJSON" }); + break; + }; + break; + }; + }); + if (ShowTableNames) tables.Select(t => t.SchemaTable).Dump(nameof(ShowTableNames)); + if (ShowTableList) tables.Dump(nameof(ShowTableList)); + DoTheComparisons(connections, tables); +} + +// Define other methods and classes here + +#region Gather Table Information + +public string GetTableQuery() +{ + var tableSchemas = string.Join(", ", SchemasAndTablesToReview.Select(sattr => $"'{sattr.SchemaName}'")); + var tableList = string.Join("\r\n", SchemasAndTablesToReview.ConvertAll(sattr => + { + if (sattr.TableNames?.Any(cn => cn == "*") ?? true) + { + return $"\r\nWHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' THEN 1"; + } + else + { + var result = ""; + if (sattr.TableNames.Any(tn => tn.Contains("%"))) + { + result += sattr.TableNames.Where(tn => tn.Contains("%")) + .Aggregate("", (x, y) => $"{x}\r\nWHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' AND c.TABLE_NAME LIKE '{y}' THEN 1"); + } + if (sattr.TableNames.Any(tn => !tn.Contains("%"))) + { + result += $"\r\nWHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' AND c.TABLE_NAME IN ({string.Join(", ", sattr.TableNames.Where(tn => !tn.Contains("%")).Select(tn => $"'{tn}'"))}) THEN 1"; + } + return result; + } + })); + return $@"SELECT c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE +, CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey +FROM INFORMATION_SCHEMA.COLUMNS AS c +LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON tc.TABLE_SCHEMA = c.TABLE_SCHEMA AND tc.TABLE_NAME = c.TABLE_NAME +LEFT OUTER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.TABLE_SCHEMA = tc.TABLE_SCHEMA AND ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME AND ccu.COLUMN_NAME = c.COLUMN_NAME +WHERE c.TABLE_SCHEMA in ({tableSchemas}) +AND (CASE {tableList} +ELSE 0 +END = 1) +AND c.DATA_TYPE NOT IN ('datetime','uniqueidentifier', 'timestamp') +AND NOT (c.COLUMN_NAME = 'RowID' and CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) = 1) +AND tc.CONSTRAINT_TYPE = 'Primary Key' +ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION"; +} + +public IList GetTables() +{ + var tableQuery = GetTableQuery(); + if (ShowTableQuery) tableQuery.Dump(nameof(ShowTableQuery)); + var tablesToRemove = SchemasAndTablesToReview.Where(sattr => sattr.ExcludeTables.Any()).SelectMany(sattr => sattr.ExcludeTables.Select(et => new { sattr.SchemaName, ExcludeTable = et })); + var tables = ExecuteQueryDynamic(tableQuery).ToList(); + if (tablesToRemove.Any()) + { + if (ShowTablesToRemove) + tablesToRemove.Dump(nameof(ShowTablesToRemove)); + tables.RemoveAll(x => tablesToRemove.Any(sattr => sattr.SchemaName == x.TABLE_SCHEMA && sattr.ExcludeTable == x.TABLE_NAME)); + } + return tables + .GroupBy(x => new { x.TABLE_SCHEMA, x.TABLE_NAME }, + (g, d) => new Table(g.TABLE_SCHEMA, g.TABLE_NAME, + d.Select(y => new Column(y.COLUMN_NAME, y.DATA_TYPE, y.IsPrimaryKey)).ToList())) + .ToList(); +} + +public class Table +{ + public string SchemaName { get; set; } + public string TableName { get; set; } + public IList Columns { get; set; } = new List(); + public IList OrderBy { get; set; } = new List(); + public IList Exclude { get; set; } = new List(); + public IList KeyColumn { get; set; } = new List(); + public IList Json { get; set; } = new List(); + public string Where { get; set; } = ""; + internal string SchemaTable => $"{SchemaName}.{TableName}"; + public string SqlSelect => $"select TOP({TopRows}) \r\n\t{SelectColumns}\r\nfrom {SchemaTable} OBJ{Where}{OrderByStatement}"; + internal string SelectColumns => !Columns?.Any() ?? true ? "*" : string.Join(",\r\n\t", Columns.Where(c => !Exclude.ToList().Contains(c.ColumnName)).Select(c => c.ColumnName)); + internal string OrderByStatement => !OrderBy?.Any() ?? true ? "" : "\r\nOrder By " + string.Join(", ", OrderBy.Select(ob => $"{ob.ColumnName}{(ob.IsDescending ? " DESC" : "")}")); + + public Table(string schemaName, string tableName) + { + SchemaName = schemaName; + TableName = tableName; + Columns = new List(); + OrderBy = new List(); + } + + public Table(string schemaName, string tableName, IEnumerable columns) + : this(schemaName, tableName) + { + Columns = columns.ToList(); + } + + public Table(string schemaName, string tableName, IEnumerable columns, IEnumerable orderBy) + : this(schemaName, tableName, columns) + { + OrderBy = orderBy.ToList(); + } + + /// + /// + /// + /// + /// Using 'D|' at the beginning of a column name implies that the sort order is descending for that column + /// + public void Init(IEnumerable orderBys = null, IEnumerable excludes = null, IEnumerable keyColumns = null, IEnumerable jsonColumns = null, string where = "") + { + Init(orderBys?.Distinct().Select(o => new OrderBy(o.Split('|').Last(), o.StartsWith("D|", StringComparison.CurrentCultureIgnoreCase))) ?? null, + excludes?.Distinct(), keyColumns?.Distinct(), jsonColumns?.Distinct(), where); + } + + /// + /// + /// + /// + /// Using 'D|' at the beginning of a column name implies that the sort order is descending for that column + /// + public void Init(IEnumerable orderBys = null, IEnumerable excludes = null, IEnumerable keyColumns = null, IEnumerable jsonColumns = null, string where = "") + { + if (orderBys != null) + OrderBys(orderBys.Where(x => Columns.Select(c => c.ColumnName).Contains(x.ColumnName))); + if (excludes != null) + Excludes(excludes.Where(x => Columns.Select(c => c.ColumnName).Contains(x))); + if (keyColumns != null) + KeyColumns(keyColumns.Where(x => Columns.Select(c => c.ColumnName).Contains(x))); + if (jsonColumns != null) + JsonColumns(jsonColumns.Where(x => Columns.Select(c => c.ColumnName).Contains(x))); + if (!string.IsNullOrEmpty(where)) + where = $"\r\nwhere {where}"; + } + + /// + /// Using 'D|' at the beginning of a column name implies that the sort order is descending for that column + /// + public void OrderBys(IEnumerable orderBys) + { + OrderBy.Clear(); + ((List)OrderBy).AddRange(orderBys.Where(o => Columns.Select(c => c.ColumnName).Contains(o.ColumnName, StringComparer.CurrentCultureIgnoreCase))); + } + + public void Excludes(IEnumerable excludes) + { + Exclude.Clear(); + ((List)Exclude).AddRange(excludes.Where(e => Columns.Select(c => c.ColumnName).Contains(e, StringComparer.CurrentCultureIgnoreCase))); + } + + public void KeyColumns(IEnumerable keyColumns) + { + KeyColumn.Clear(); + ((List)KeyColumn).AddRange(keyColumns.Where(kc => Columns.Select(c => c.ColumnName).Contains(kc, StringComparer.CurrentCultureIgnoreCase))); + KeyColumn.Reverse().ToList().ForEach(kc => { + var col = Columns.Single(c => c.ColumnName == kc); + Columns.Remove(col); + Columns.Insert(0, col); + }); + } + + public void JsonColumns(IEnumerable jsonColumns) + { + Json.Clear(); + ((List)Json).AddRange(jsonColumns.Where(jc => Columns.Select(c => c.ColumnName).Contains(jc, StringComparer.CurrentCultureIgnoreCase))); + } +} + +public class Column +{ + public string ColumnName { get; set; } + public string DataType { get; set; } + public bool IsPrimaryKey { get; set; } + public Column(string columnName, string dataType = "", bool isPrimaryKey = false) + { + ColumnName = columnName; + DataType = dataType; + IsPrimaryKey = isPrimaryKey; + } +} + +public class OrderBy +{ + public string ColumnName { get; set; } + public bool IsDescending { get; set; } = false; + + public OrderBy(string columnName, bool isDescending = false) + { + ColumnName = columnName; + IsDescending = isDescending; + } + +} + +public class TablesAndColumns +{ + public string SchemaName { get; set; } + public IEnumerable TableNames { get; set; } + public IEnumerable ExcludeTables { get; set; } + public TablesAndColumns(string schemaName, IEnumerable tables = null, IEnumerable excludeTables = null) + { + SchemaName = schemaName; + TableNames = tables ?? new string[] { "*" }; + ExcludeTables = excludeTables ?? new string[] { }; + } +} + +public class OrderByInformation +{ + public string TableName { get; set; } + public IEnumerable OrderBy { get; set; } + public OrderByInformation(string tableName, IEnumerable columns) + { + TableName = tableName; + OrderBy = columns + .Select(c => + new OrderBy(c.StartsWith("D|") ? c.Substring(2) : c, + c.StartsWith("D|"))); + } +} + +public class ColumnsToExclude +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public ColumnsToExclude(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +public class JsonColumns +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public JsonColumns(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +#endregion + +#region Do the comparisons + +public void DoTheComparisons(Connections connections, IEnumerable
tables) +{ + foreach (var table in tables) + { + var sql = table.SqlSelect; + var dataLegacy = GetData(connections.Legacy, sql, table.TableName).AsEnumerable().ToList(); + var dataUpdate = GetData(connections.Update, sql, table.TableName).AsEnumerable().ToList(); + + var compare = new List(); + var jsonColumns = table.Json.ToList() ?? null; + var keyColumns = table.KeyColumn.ToList() ?? null; + var idx = 0; + dataLegacy + .ForEach(legacyRow => + { + DataRow updateRow = default(DataRow); + if (table.KeyColumn.Any()) + { + var keys = string.Join("|", table.KeyColumn.Select(kc => $"{legacyRow.Field(kc)}")); + updateRow = dataUpdate + .FirstOrDefault(y => keys == string.Join("|", table.KeyColumn.Select(kc => $"{y.Field(kc)}"))); + } + else + { + if (dataUpdate.Count() > idx) + updateRow = dataUpdate[idx++]; + } + if ((ShowMissingUpdate && updateRow == null) || + (updateRow != null && JsonConvert.SerializeObject(legacyRow.ItemArray) != JsonConvert.SerializeObject(updateRow.ItemArray))) + compare.Add(new CompareSet(compare.Count, legacyRow, updateRow, jsonColumns, keyColumns)); + }); + if (ShowMissingLegacy && table.KeyColumn.Any()) + { + dataUpdate + .ForEach(updateRow => + { + DataRow legacyRow = default(DataRow); + if (table.KeyColumn.Any()) + { + var keys = string.Join("|", table.KeyColumn.Select(kc => $"{updateRow.Field(kc)}")); + legacyRow = dataLegacy + .FirstOrDefault(y => keys == string.Join("|", table.KeyColumn.Select(kc => $"{y.Field(kc)}"))); + } + if (legacyRow == null) + compare.Add(new CompareSet(compare.Count, legacyRow, updateRow, jsonColumns, keyColumns)); + }); + } + if (compare.Any()) + { + compare.OrderBy(c => c.OrderBy) + .Dump($"{table.SchemaTable} ( {compare.Count()} / {dataLegacy.Count} / {dataUpdate.Count} rows )", TableDumpDepth); + } + else + { + "No differences found in data".Dump($"{table.SchemaTable} ( 0 / {dataLegacy.Count} / {dataUpdate.Count} rows )"); + } + } +} + +public class Connections +{ + public ServerInstance Legacy { get; set; } + public ServerInstance Update { get; set; } +} + +public class ServerInstance +{ + public string Server { get; set; } + public string Database { get; set; } + + public ServerInstance(string server, string database) + { + Server = server; + Database = database; + } +} + +public DataTable GetData(ServerInstance serverInstance, string sql, string tableName) +{ + var server = serverInstance.Server; + var database = serverInstance.Database; + var connStr = $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;"; + using (var conn = new SqlConnection(connStr)) + { + var datatable = new DataTable(); + var adapter = new SqlDataAdapter(sql, conn); + try + { + adapter.Fill(datatable); + } + catch (Exception) + { + sql.Dump(nameof(sql)); + throw; + } + datatable.TableName = tableName; + return datatable; + } +} + +public class CompareSet +{ + internal int Row { get; set; } + internal IList ColumnNames { get; set; } + internal IList Legacy { get; set; } + internal IList Update { get; set; } + internal int OrderBy { get; set; } = 0; + public IList Rows { get; set; } + internal IList JsonColumns { get; set; } + internal IList KeyColumns { get; set; } + public CompareSet(int row, DataRow right, DataRow left, IList jsonColumns, IList keyColumns) + { + Row = ++row; + if (right == null) + { + ColumnNames = left.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + } + else + { + ColumnNames = right.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + } + Legacy = right?.ItemArray.ToList(); + Update = left?.ItemArray.ToList(); + OrderBy = (right != null ? 0 : 2) + (left != null ? 0 : 1); + JsonColumns = jsonColumns ?? new List(); + KeyColumns = keyColumns ?? new List(); + Rows = ColumnNames.Select((c, i) => new Row(row, c, Legacy?[i], Update?[i], JsonColumns?.Contains(c, StringComparer.CurrentCultureIgnoreCase) ?? false)).ToList(); + } + + public CompareSet(int row, DataRow right, DataRow left) + : this(row, right, left, null, null) + { + } + + object ToDump() => new + { + Row = $"{Row}", + Rows = Rows.Select(x => new + { + Column = (x.Left ?? "").Equals(x.Right ?? "") + ? KeyColumns.Contains((string)x.Column) + ? new XElement("LINQPad.HTML", new XElement("div", new XAttribute("style", "background-color:cyan;color:black"), x.Column)) + : (object)x.Column + : new XElement("LINQPad.HTML", new XElement("div", new XAttribute("style", "background-color:lightyellow;color:black"), x.Column)), + Legacy = x.Left, + Update = x.Right + }) + }; + +} + +public class Row +{ + public int RowId { get; set; } + public string Column; + public bool IsJson; + public object Left; + public object Right; + + public Row(int row, string column, object left, object right) + { + RowId = row; + Column = column; + Left = left; + Right = right; + } + + public Row(int row, string column, object left, object right, bool isJson) + : this(row, column, left, right) + { + + IsJson = isJson; + if (!isJson) return; + if (left != null) + { + Left = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(left.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + } + if (right != null) + { + Right = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(right.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + } + } + +} + +#endregion \ No newline at end of file diff --git a/DB Query with Lambda Expressions.linq b/DB Query with Lambda Expressions.linq new file mode 100644 index 0000000..4223411 --- /dev/null +++ b/DB Query with Lambda Expressions.linq @@ -0,0 +1,460 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + <RuntimeDirectory>\System.Linq.Expressions.dll + <RuntimeDirectory>\System.Linq.Queryable.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Linq.Dynamic + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private List SchemasAndTablesToReview = new List(); +private List OrderByStatements = new List(); +private List ColumnsToBeExcluded = new List(); +private List JsonColumnsToBeParsed = new List(); +private Dictionary JoinClauses = new Dictionary(); +private static Dictionary WhereClauses = new Dictionary(); +public static int TopRows = 1000;//int.MaxValue; + +void Main() +{ + SchemasAndTablesToReview.Clear(); + SchemasAndTablesToReview.Add(new TablesAndColumns("cci", new[] {"VariationOpportunity"})); + WhereClauses.Clear(); + WhereClauses.Add("clientdss.FactPatientEncounterSummary", "OBJ.MSDRGCaseTypeFamilyID <> 0 OR OBJ.APRDRGCaseTypeFamilyID <> 0"); + OrderByStatements.AddRange(new[] + { + new OrderByInformation("cci.InitiativeWorkflowHistory", new [] {"FromStep","ToStep"}), + new OrderByInformation("cci.VariationEncounterSavingInfo", new []{"EncounterRecordNumber","PhysicianID"}), + new OrderByInformation("cci.FactOpportunityMetric", new []{"FiscalYearID","FiscalMonthID"}), + new OrderByInformation("cci.FactOpportunitySavings", new []{"FiscalyYearID","FiscalMonthID"}), + new OrderByInformation("cci.Initiative", new []{"Name"}), + new OrderByInformation("cci.VariationOpportunity", new []{"CaseTypeEntityId", "CostDriver"}), + new OrderByInformation("clientdss.FactPatientEncounterSummary", new []{"EncounterRecordNumber"}), + new OrderByInformation("dss.CaseTypeFamily", new []{"Name", "CaseTypeFamilyGlobalID", "CaseTypeFamilyID"}), + new OrderByInformation("dss.CaseTypeFamilyMappingCPT", new []{"CPTCode", "CaseTypeFamilyVersionID", "CaseTypeFamilyID"}), + new OrderByInformation("dss.DimCaseType", new []{"CaseTypeFamilyID", "CaseTypeId", "Name"}) + }); + JoinClauses.Clear(); + JoinClauses.Add("cci.VariationOpportunity", "new(CaseTypeEntityId as firstKey, CostDriver as secondKey)"); + ColumnsToBeExcluded.AddRange(new[] + { + new ColumnsToExclude("cci.SystemSetting", new [] {"IsEncrypted"}), + new ColumnsToExclude("cci.Configuration", new [] {"InitiativeIsSimplifiedWorkflow"}), + new ColumnsToExclude("clientdss.FactPatientEncounterSummary", new [] {"MikeQAtest1ID", "CustomJesseValidatingAllOthers", "CustomNewCalculatedSystemFieldasdf"}) + }); + JsonColumnsToBeParsed.AddRange(new[] + { + new JsonColumns("dss.DimCaseType", new [] {"CaseTypeConfigJSON"}) + }); + + var tables = GetTables(); + var connections = new Connections { + Legacy = new ServerInstance("D0001-SQL-11.sdt.local", "jazz tst master prod 20190708.1"), + Update = new ServerInstance("D0001-SQL-11.sdt.local","jazz tst master prod") + }; + DoTheComparisons(connections, tables); +} + +// Define other methods and classes here + +#region Gather Table Information + +public string GetTableQuery() +{ + var tableSchemas = string.Join(", ", SchemasAndTablesToReview.Select(sattr => $"'{sattr.SchemaName}'")); + var tableList = string.Join("\r\n", SchemasAndTablesToReview.ConvertAll(sattr => + { + if (sattr.TableNames?.Any(cn => cn == "*") ?? true) + { + return $"WHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' THEN 1"; + } + else + { + return $"WHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' AND c.TABLE_NAME IN ({string.Join(", ", sattr.TableNames.Select(cn => $"'{cn}'"))}) THEN 1"; + } + })); + return $@"SELECT c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE +, CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey +FROM INFORMATION_SCHEMA.COLUMNS AS c +LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON tc.TABLE_SCHEMA = c.TABLE_SCHEMA AND tc.TABLE_NAME = c.TABLE_NAME +LEFT OUTER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.TABLE_SCHEMA = tc.TABLE_SCHEMA AND ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME AND ccu.COLUMN_NAME = c.COLUMN_NAME +WHERE c.TABLE_SCHEMA in ({tableSchemas}) +AND (CASE +{tableList} +ELSE 0 +END = 1) +AND c.DATA_TYPE NOT IN ('datetime','uniqueidentifier', 'timestamp') +AND NOT (c.COLUMN_NAME = 'RowID' and CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) = 1) +AND tc.CONSTRAINT_TYPE = 'Primary Key' +ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION"; +} + +public IList
GetTables() +{ + var tableQuery = GetTableQuery(); + return ExecuteQueryDynamic(tableQuery) + .GroupBy(x => new { x.TABLE_SCHEMA, x.TABLE_NAME }, (g, d) => new Table + { + SchemaName = g.TABLE_SCHEMA, + TableName = g.TABLE_NAME, + Columns = d + .Select(y => new Column + { + ColumnName = y.COLUMN_NAME, + DataType = y.DATA_TYPE, + IsPrimaryKey = y.IsPrimaryKey + }), + OrderBy = OrderByStatements?.SingleOrDefault(obs => obs.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.OrderBy, + Exclude = ColumnsToBeExcluded?.SingleOrDefault(ctbe => ctbe.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.ColumnNames ?? new List(), + Json = JsonColumnsToBeParsed?.SingleOrDefault(ctbe => ctbe.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.ColumnNames ?? new List(), + Where = WhereClauses.ContainsKey($"{g.TABLE_SCHEMA}.{g.TABLE_NAME}") ? $"\r\nwhere {WhereClauses[$"{g.TABLE_SCHEMA}.{g.TABLE_NAME}"]}" : "" + }).ToList(); +} + +public class Table +{ + public string SchemaName { get; set; } + public string TableName { get; set; } + public IEnumerable Columns { get; set; } + public IEnumerable OrderBy { get; set; } + public IEnumerable Exclude { get; set; } + public IEnumerable Json { get; set; } + public string Where { get; set; } = ""; + internal string SchemaTable => $"{SchemaName}.{TableName}"; + public string SqlSelect => $"select TOP({TopRows}) \r\n\t{SelectColumns}\r\nfrom {SchemaTable} OBJ{Where}{OrderByStatement}"; + internal string SelectColumns => !Columns?.Any() ?? true ? "*" : string.Join(",\r\n\t", Columns.Where(c => !Exclude.ToList().Contains(c.ColumnName)).Select(c => c.ColumnName)); + internal string OrderByStatement => !OrderBy?.Any() ?? true ? "" : "\r\nOrder By " + string.Join(", ", OrderBy.Select(ob => $"{ob.ColumnName}{(ob.IsDescending ? " DESC" : "")}")); +} + +public class Column +{ + public string ColumnName { get; set; } + public string DataType { get; set; } + public bool IsPrimaryKey { get; set; } +} + +public class OrderBy +{ + public string ColumnName { get; set; } + public bool IsDescending { get; set; } = false; +} + +public class TablesAndColumns +{ + public string SchemaName { get; set; } + public IEnumerable TableNames { get; set; } + public TablesAndColumns(string schemaName, IEnumerable tables) + { + SchemaName = schemaName; + TableNames = tables; + } +} + +public class OrderByInformation +{ + public string TableName { get; set; } + public IEnumerable OrderBy { get; set; } + public OrderByInformation(string tableName, IEnumerable columns) + { + TableName = tableName; + OrderBy = columns.Select(c => new OrderBy + { + ColumnName = c.StartsWith("D|") ? c.Substring(2) : c, + IsDescending = c.StartsWith("D|") + }); + } +} + +public class ColumnsToExclude +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public ColumnsToExclude(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +public class JsonColumns +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public JsonColumns(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +#endregion + +#region Do the comparisons + +public void DoTheComparisons(Connections connections, IEnumerable
tables) +{ + foreach (var table in tables) + { + var sql = table.SqlSelect; + var dataLegacy = GetData(connections.Legacy, sql, table.TableName); + var dataUpdate = GetData(connections.Update, sql, table.TableName); + + var legacy = dataLegacy.Rows; + var update = dataUpdate.Rows; + ParameterExpression pe1 = Expression.Parameter(dataLegacy.Columns["CaseTypeEntityId"].DataType, "CaseTypeEntityId"); + ParameterExpression pe2 = Expression.Parameter(dataLegacy.Columns["CostDriver"].DataType, "CostDriver"); + IQueryable legacyTable = dataLegacy.AsEnumerable().AsQueryable(); + IEnumerable updateTable = dataUpdate.AsEnumerable(); + var query = legacyTable.Join( + updateTable, + "new(get_Item(4) as CostDriver, get_Item(34) as CaseTypeEntityId)", + "new(get_Item(4) as CostDriver, get_Item(34) as CaseTypeEntityId)", + "new(outer as legacy, inner as update)" + ); + LambdaExpression le = System.Linq.Dynamic.DynamicExpression.ParseLambda(dataLegacy.AsEnumerable().AsQueryable().ElementType, + null, "new(CaseTypeEntityId as FirstKey, CostDriver as SecondKey)", "new( + // var test = update.AsQueryable().MyJoin(legacy.AsQueryable(), "new(CaseTypeEntityId as firstKey, CostDriver as secondKey)", +// "new(CaseTypeEntityId as firstKey, CostDriver as secondKey)", +// "new inner as legacy, outer as update)"); + var idxCount = legacy.Count; + var compare = new List(); + var jsonColumns = tables.SingleOrDefault(t => t.SchemaTable == table.TableName)?.Json.ToList(); + foreach (var row in Enumerable.Range(0, idxCount)) + { + var r = legacy[row]; + if (row < update.Count) + { + var u = update[row]; + var rJson = JsonConvert.SerializeObject(r.ItemArray); + var uJson = JsonConvert.SerializeObject(u.ItemArray); + if (rJson != uJson) + { + if (jsonColumns == null) + { + compare.Add(new CompareSet(r, u)); + } + else + { + compare.Add(new CompareSet(r, u, jsonColumns)); + } + } + } + else + { + if (jsonColumns == null) + { + compare.Add(new CompareSet(r, null)); + } + else + { + compare.Add(new CompareSet(r, null, jsonColumns)); + } + } + } + if (compare.Any()) + { + compare.Dump($"{table.TableName} ({compare.Count()}/{dataLegacy.Rows.Count} rows)", 2); + } + else + { + "No differences found in data".Dump($"{table.TableName} (0/{dataLegacy.Rows.Count} rows)"); + } + } +} + +/* +public static IQueryable MyJoin(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values) +{ + if (inner == null) throw new ArgumentNullException("inner"); + if (outerSelector == null) throw new ArgumentNullException("outerSelector"); + if (innerSelector == null) throw new ArgumentNullException("innerSelector"); + if (resultsSelector == null) throw new ArgumentNullException("resultsSelctor"); + + LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(outer.ElementType, null, outerSelector, values); + LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(inner.AsQueryable().ElementType, null, innerSelector, values); + + ParameterExpression[] parameters = new ParameterExpression[] { + Expression.Parameter(outer.ElementType, "outer"), Expression.Parameter(inner.AsQueryable().ElementType, "inner") }; + LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, resultsSelector, values); + + return outer.Provider.CreateQuery( + Expression.Call( + typeof(Queryable), "Join", + new Type[] { outer.ElementType, inner.AsQueryable().ElementType, outerSelectorLambda.Body.Type, resultsSelectorLambda.Body.Type }, + outer.Expression, inner.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultsSelectorLambda))); +} + +public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values) +{ + return (IQueryable)Join((IQueryable)outer, (IEnumerable)inner, outerSelector, innerSelector, resultsSelector, values); +} +*/ +public class Connections +{ + public ServerInstance Legacy { get; set; } + public ServerInstance Update { get; set; } +} + +public class ServerInstance +{ + public string Server { get; set; } + public string Database { get; set; } + + public ServerInstance(string server, string database) + { + Server = server; + Database = database; + } +} + +public DataTable GetData(ServerInstance serverInstance, string sql, string tableName) +{ + var server = serverInstance.Server; + var database = serverInstance.Database; + var connStr = $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;"; + using (var conn = new SqlConnection(connStr)) + { + var datatable = new DataTable(); + var adapter = new SqlDataAdapter(sql, conn); + try + { + adapter.Fill(datatable); + } + catch (Exception ex) + { + sql.Dump(nameof(sql)); + throw; + } + datatable.TableName = tableName; + return datatable; + } +} + +public class CompareSet +{ + internal IList ColumnNames { get; set; } + internal IList Legacy { get; set; } + internal IList Update { get; set; } + public IList Rows { get; set; } + internal IList JsonColumns { get; set; } + public CompareSet(DataRow right, DataRow left) + { + ColumnNames = right.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + Legacy = right.ItemArray.ToList(); + Update = left?.ItemArray.ToList(); + Rows = ColumnNames.Select((c, i) => new Row(c, Legacy[i], Update?[i])).ToList(); + } + public CompareSet(DataRow right, DataRow left, IList jsonColumns) + { + ColumnNames = right.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + Legacy = right.ItemArray.ToList(); + Update = left?.ItemArray.ToList(); + JsonColumns = jsonColumns; + Rows = ColumnNames.Select((c, i) => new Row(c, Legacy[i], Update?[i], JsonColumns.Contains(c, StringComparer.CurrentCultureIgnoreCase))).ToList(); + } + +} + +public class Row +{ + public string Column; + public bool IsJson; + public object Left; + public object Right; + + public Row(string column, object left, object right) + { + Column = column; + Left = left; + Right = right; + } + + public Row(string column, object left, object right, bool isJson) + : this(column, left, right) + { + IsJson = isJson; + if (!isJson) return; + Left = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(left.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + if (right == null) return; + Right = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(right.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + } + + object ToDump() => new + { + Column = Left.Equals(Right ?? "") ? (object)Column : new XElement("LINQPad.HTML", new XElement("div", new XAttribute("style", "background-color:lightyellow;color:black"), Column)), + Legacy = Left, + Update = Right + }; +} + +#endregion \ No newline at end of file diff --git a/DDEN SQL Server List.linq b/DDEN SQL Server List.linq new file mode 100644 index 0000000..84e9281 --- /dev/null +++ b/DDEN SQL Server List.linq @@ -0,0 +1,66 @@ + + + 877f607f-de79-449a-a047-e6d0c5b9e5d2 + true + DDEN-SQL-SMC-01.sdt.local + smc dev + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var dbInformation = (from dbInfo in ViewDatabaseInfo +where dbInfo.IsProduction.HasValue && dbInfo.IsProduction.Value +orderby dbInfo.Description, dbInfo.DatabaseName +select dbInfo); +dbInformation +.Dump(); \ No newline at end of file diff --git a/Dashboard extrapolation.linq b/Dashboard extrapolation.linq new file mode 100644 index 0000000..a477bda --- /dev/null +++ b/Dashboard extrapolation.linq @@ -0,0 +1,148 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.Dynamic + + +var emptyGuid = Guid.Empty.ToString(); +var dashboards = (from dashboard in DesktopTemplates + join module in SystemCenterModules on dashboard.ModuleGUID equals module.ModuleGUID + join solution in SystemCenterSolutions on module.SolutionGUID equals solution.SolutionGUID + where dashboard.IsLegacy == false && solution.IsStatusDisabled == false + select new + { + solution = solution.Name, + primarySort = solution.SortOrder, + module = module.Name, + categories = module.SystemCenterCategories + .Where(c => c.IsMaintenanceMode == true).OrderBy(c => c.SortOrder) + .Select(c => new { c.Name, SortOrder = c.SortOrder.ToString() }).ToList(), + secondarySort = module.SortOrder, + dashboard.DesktopTemplateGUID, + dashboard.Name, + dashboard.Description, + parameters = dashboard.DesktopParameters.Any() + ? dashboard.DesktopParameters.Select(p => new + { + p.Name, + p.ColumnName, + p.DimensionName, + p.AttributeName, + p.DataSourceGUID, + ExcludedWidgetGuids = string.IsNullOrEmpty(p.ExcludedWidgetGuidsCSV) ? null : p.ExcludedWidgetGuidsCSV.Split(',') + }).Distinct().ToList() + : null, + // columns = dashboard.DesktopColumns.Any() ? dashboard.DesktopColumns.ToList() : null, + widgets = dashboard.DashboardWidgets.Any() + ? dashboard.DashboardWidgets.Select(w => new + { + w.Name, + w.Row, + w.Col, + w.Height, + w.Width, + w.WidgetClassName, + DataSourceGUID = w.DataSourceGUID.ToString() == "00000000-0000-0000-0000-000000000000" ? "" : w.DataSourceGUID.ToString(), + WidgetJSON = (JsonConvert.DeserializeObject(w.WidgetJSON) as IDictionary) + }) + .Select(w => new + { + w.Name, + w.Row, + w.Col, + w.Height, + w.Width, + w.WidgetClassName, + w.DataSourceGUID, + w.WidgetJSON, + ReportGuid = w.WidgetClassName == "Grid" || w.WidgetClassName == "Chart" || + (w.WidgetClassName == "Metric" && w.WidgetJSON["ReportGuid"] != emptyGuid) + ? w.WidgetJSON["ReportGuid"] + : null + }) + .OrderBy(w => w.Row).ThenBy(w => w.Col).ToList() + : null, + desktop = dashboard.DesktopWidgets.Any() + ? dashboard.DesktopWidgets.Select(w => new + { + w.Name, + w.Height, + w.DesktopTemplateGUID, + w.WidgetFullName, + w.WidgetXML + }).ToList() + : null + }) +.OrderBy(x => x.primarySort).ThenBy(x => x.secondarySort).ThenBy(x => x.Name).ToList(); +dashboards.Dump(); +dashboards.Where(d => d.parameters != null).SelectMany(d => d.parameters) +.OrderBy(d => d.DimensionName).ThenBy(d => d.AttributeName).Dump(); +dashboards.SelectMany(d => d.widgets.Where(w => w.WidgetClassName == "Report" || w.WidgetClassName == "Chart") + .Select(w => new {Dashboard = d.Name, Report = w.Name, w.Row, w.Col, w.Height, w.Width, w.WidgetClassName, w.DataSourceGUID, w.ReportGuid})) +.OrderBy(d => d.Dashboard).ThenBy(d => d.Report).Dump(); +dashboards.SelectMany(d => d.widgets.Where(w => w.WidgetClassName == "Metric") + .Select(w => new { Dashboard = d.Name, Report = w.Name, w.Row, w.Col, w.Height, w.Width, w.WidgetClassName, w.DataSourceGUID, w.WidgetJSON })) +.OrderBy(d => d.Dashboard).ThenBy(d => d.Report).Dump(); \ No newline at end of file diff --git a/DateTime Differences.linq b/DateTime Differences.linq new file mode 100644 index 0000000..ae0b8d4 --- /dev/null +++ b/DateTime Differences.linq @@ -0,0 +1,84 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + TimePeriodLibrary.NET + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Itenso.TimePeriod + + +var date1 = DateTime.Now.AddMonths(-6); +date1.Dump(); + +var date2 = DateTime.Now.AddMonths(-19).AddDays(-14).AddHours(-25); +date2.Dump(); +"".PadLeft(40, '=').Dump(); +var tock = date1.Subtract(date2).Ticks; + +TimeSpan ts = date1 - date2; +$"{ts.TotalDays} Days".Dump(); +"".PadLeft(40, '-').Dump(); + +var dateDiff = new DateDiff(date2, date1); +$"{dateDiff.ElapsedYears} Years {dateDiff.ElapsedMonths} Months {dateDiff.ElapsedDays} Days".Dump(); + +"".PadLeft(40, '-').Dump(); +var xx = new DateTime(Math.Abs(tock)); +xx.Dump(); +xx.Year.Dump(); +xx.Month.Dump(); +xx.Day.Dump(); \ No newline at end of file diff --git a/DateTime Extensions Tester.linq b/DateTime Extensions Tester.linq new file mode 100644 index 0000000..aa8397f --- /dev/null +++ b/DateTime Extensions Tester.linq @@ -0,0 +1,99 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + AWSSDK.Glue + AWSSDK.S3 + FluentAssertions + Newtonsoft.Json + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + FluentAssertions + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + for (var x = 0; x > -5; x--) + { + try + { + var testDate = DateTime.Now.AddYears(x); + testDate.Dump($"{x}"); + RunValidation(testDate); + } + catch (Exception ex) + { + $"{x} - {ex.Message}".Dump(); + } + } +} + +public void RunValidation(DateTime testDate) +{ + testDate.AddMilliseconds(-1).GetPrettyDate().Should().Be("just now"); + testDate.AddSeconds(-1).GetPrettyDate().Should().Be("just now"); + testDate.AddMinutes(-1).GetPrettyDate().Should().Be("1 minute ago"); + for (var x = -2; x >= -59; x--) + { + testDate.AddMinutes(-x).GetPrettyDate().Should().Be($"{x} minutes ago"); + } + testDate.AddHours(-1).GetPrettyDate().Should().Be("1 hour ago"); + for (var x = -2; x >= -23; x--) + { + testDate.AddHours(-x).GetPrettyDate().Should().Be($"{x} hours ago"); + } + testDate.AddDays(-1).GetPrettyDate().Should().Be("yesterday"); + for (var x = -2; x >= -364; x--) + { + testDate.AddDays(-x).GetPrettyDate().Should().Be($"{x} days ago"); + } + testDate.AddMonths(-1).GetPrettyDate().Should().Be("5 weeks ago"); + for (var x = -2; x >= -364; x--) + { + testDate.AddMonths(-x).GetPrettyDate().Should().Be($"{x} months ago"); + } +} + +// Define other methods and classes here diff --git a/DepartmentPatientCensus Analysis.linq b/DepartmentPatientCensus Analysis.linq new file mode 100644 index 0000000..40427e3 --- /dev/null +++ b/DepartmentPatientCensus Analysis.linq @@ -0,0 +1,95 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + jazz tst CNE 20191210.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var configurationGuid = Guid.Parse("880C4912-5A58-40B7-ADB1-1F9BD365E6AF"); + var configuration = (from c in Configurations where c.ConfigurationGUID == configurationGuid select c).Single(); + //configuration.Dump(nameof(configuration)); + var baselineEndDate = configuration.WasteEndDate; + var baselineStartDate = baselineEndDate.AddYears(-1).AddDays(1); + (from dpc in DepartmentPatientCensus + where dpc.EnterTime < baselineEndDate && dpc.ExitTime > baselineStartDate + select new { dpc.RowID, dpc.DepartmentID, dpc.EncounterRecordNumber, dpc.EnterTime, dpc.ExitTime, dpc.IsNewborn, baselineStartDate, baselineEndDate }) + .ToList() + .GroupBy(ed => new { ed.DepartmentID, ed.EnterTime.Year, ed.EnterTime.Month, ed.EnterTime.Day, ed.EnterTime.Hour }, (g, d) => d.Select(x => new + { + g.DepartmentID, + g.Year, + g.Month, + g.Day, + g.Hour, + newbornEncounters = d.Where(y => y.IsNewborn).Count(), + encounters = d.Where(y => !y.IsNewborn).Count() + }).First()) + .Where(ed => new[] { 21398, 21915 }.Contains(ed.DepartmentID)) + .GroupBy(ed => ed.DepartmentID, (g, d) => new + { + DepartmentId = g, + Data = d.OrderBy(ed => ed.Year) + .ThenBy(ed => ed.Month) + .ThenBy(ed => ed.Day) + .ThenBy(ed => ed.Hour) + }) + .Dump(); +} + +// Define other methods and classes here diff --git a/Dev Page Logs.linq b/Dev Page Logs.linq new file mode 100644 index 0000000..b944285 --- /dev/null +++ b/Dev Page Logs.linq @@ -0,0 +1,71 @@ + + + a0281727-8f99-469c-a1e8-bda14dcbf030 + true + DDEN-SQL-LOG-01.sdt.local + jazz log dev + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +PageLogs.OrderByDescending(p => p.RowId) +.Where(p => p.UserName.Contains("tlamb")) +//.Between(p => p.RowId, 4826093, 4826100) +.Take(100).Dump(); +//Mapping.GetTables().Where(t => t.TableName == "[PageLog]") +//.First().RowType.DataMembers +//.Where(dm => dm.DbType != null) +//.Select( dm => new {dm.Name, dm.DbType, dm.Type, dm.MappedName, dm.IsPrimaryKey}) +//.Dump(); +// \ No newline at end of file diff --git a/DimCaseType QA Master.linq b/DimCaseType QA Master.linq new file mode 100644 index 0000000..68e6aca --- /dev/null +++ b/DimCaseType QA Master.linq @@ -0,0 +1,92 @@ + + LinqToCsv + LINQtoCSV + Newtonsoft.Json + + +void Main() +{ + var thefile = @"D:\Users\tlamb\Downloads\DimCaseType QA Master.csv"; + var csvdata = File.ReadAllLines(thefile); + //csvdata.Dump(); + var inputFileDescription = new CsvFileDescription + { + SeparatorChar = ',', + FirstLineHasColumnNames = false, + EnforceCsvColumnAttribute = true, + IgnoreUnknownColumns = true, + UseFieldIndexForReadingData = true + }; + var cc = new CsvContext(); + var data = cc.Read(thefile, inputFileDescription).ToList(); + //data.Dump(); + string.Join("\r\n", + data.ConvertAll(d => $"UPDATE dss.DimCaseType SET CaseTypeConfigJSON = '{d.CaseTypeConfigJSON}' WHERE Name = '{d.Name}' and CaseTypeID = {d.CaseTypeID};")).Dump(); +} + +// Define other methods and classes here +public class DimCaseType +{ + [CsvColumn(FieldIndex = 1)] + public int CaseTypeID { get; set; } + [CsvColumn(FieldIndex = 2)] + public string Name { get; set; } + [CsvColumn(FieldIndex = 3)] + public string CaseTypeConfigJSON { get; set; } + //public MSDRGCaseTypeConfiguration CaseTypeConfig => JsonConvert.DeserializeObject(CaseTypeConfigJSON); +} + +public class CaseTypeConfiguration +{ + public int PhysicianMinVolume { get; set; } = 0; +} + +public class DRGCaseTypeConfiguration : CaseTypeConfiguration +{ + public List AgeCohortIDInclusions { get; set; } = new List(); + public List PhysicianIDExclusions { get; set; } = new List(); + public StandardDeviationExclusions StandardDeviationExcludedTypeEnum { get; set; } = StandardDeviationExclusions.None; + public int LengthOfStayThreshold { get; set; } = 0; + public HashSet CPTCodes { get; set; } = new HashSet(); + public List PatientTypeRollupIDInclusions { get; set; } = new List(); +} + +public class MSDRGCaseTypeConfiguration : DRGCaseTypeConfiguration +#pragma warning restore S101 // Types should be named in PascalCase +{ + public HashSet CCMCCCategories { get; set; } = new HashSet(); + +} + +public enum CCMCCCategoryTypes +#pragma warning restore S2342 // Enumeration types should comply with a naming convention +{ + None, + CC, + MCC, + WO, + NA, + CCMCC +} + +public enum StandardDeviationExclusions +{ + None = 0, + TwoStdDev = 1, + ThreeStdDev = 2, + CustomLOSOutlier = 3 +} + +public enum PhysicianGroupingTypes +{ + Physician = 0, + Specialty = 1, + GroupAffiliation = 2 +} + +public enum CaseTypeCategories +{ + MSDRG = 0, + APRDRG = 1, + PatientPopulation = 2 +} diff --git a/Dynamic JSON object.linq b/Dynamic JSON object.linq new file mode 100644 index 0000000..5900e24 --- /dev/null +++ b/Dynamic JSON object.linq @@ -0,0 +1,9 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + + +var jsonStr = "[{\"HierarchyPath\":\"DEPT|DEPT|1|1|27|2|162\",\"Name\":\"10 - 2530 - NSMC IU NICU\"},{\"HierarchyPath\":\"DEPT|DEPT|1|1|27|2|266\",\"Name\":\"10 - 4000 - SL OPERATING ROOM\"}]"; +dynamic obj = JsonConvert.DeserializeObject(jsonStr); +string test = obj[0].HierarchyPath; +test.Dump(); \ No newline at end of file diff --git a/Encounter Performance Engine test.linq b/Encounter Performance Engine test.linq new file mode 100644 index 0000000..025353c --- /dev/null +++ b/Encounter Performance Engine test.linq @@ -0,0 +1,155 @@ + + + 580b3b8d-cc02-4a68-8fbd-d1ec374a25f2 + true + D0001-sql-11.sdt.local + jazz dev master Prod + true + + Newtonsoft.Json + Newtonsoft.Json.Linq + + +void Main() +{ + var oppGuid = Guid.Parse("ebe53c65-af17-4372-b7c1-18a6011f7d23"); + var opp = from eo in EncounterOpportunities + where eo.OpportunityGUID == oppGuid + select eo; + + var pti = from eopti in EncounterOpportunityPerformanceTrackingItems + where eopti.OpportunityGUID == oppGuid + orderby eopti.LevelID, eopti.Type + select new { performanceTrackingItem = JsonConvert.DeserializeObject(eopti.PerformanceTrackingItem) }; + + var metrics = from eopemd in EncounterOpportunityPerformanceEngineMetricData + where eopemd.OpportunityGUID == oppGuid + orderby eopemd.LevelID, eopemd.IsBaseline, eopemd.Type + select new + { + eopemd.LevelID, + eopemd.Type, + eopemd.IsBaseline, + months = new[] { + new {Name = "Month01", Value = eopemd.Month01}, + new {Name = "Month02", Value = eopemd.Month02}, + new {Name = "Month03", Value = eopemd.Month03}, + new {Name = "Month04", Value = eopemd.Month04}, + new {Name = "Month05", Value = eopemd.Month05}, + new {Name = "Month06", Value = eopemd.Month06}, + new {Name = "Month07", Value = eopemd.Month07}, + new {Name = "Month09", Value = eopemd.Month08}, + new {Name = "Month09", Value = eopemd.Month09}, + new {Name = "Month10", Value = eopemd.Month10}, + new {Name = "Month11", Value = eopemd.Month11}, + new {Name = "Month12", Value = eopemd.Month12} + } + }; + + //var jsonPti = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(pti[1]), Newtonsoft.Json.Formatting.Indented); + //jsonPti.Dump(); + opp.Dump(nameof(EncounterOpportunities)); + metrics.Dump(nameof(EncounterOpportunityPerformanceEngineMetricData)); + pti.FirstOrDefault().Dump(nameof(EncounterOpportunityPerformanceTrackingItems)); +} + +// Define other methods and classes here + +public class PerformanceMonthlyUnitData +{ + public int MonthID { get; set; } + public double RampUp { get; set; } + public double Units { get; set; } + public double UnitsYTD { get; set; } + public double Stats { get; set; } + public double StatsYTD { get; set; } + + /// + /// Units DivideBy Stats + /// + public double UnitsPerStat { get; set; } + public double UnitsPerStatYTD { get; set; } +} + +public class PerformanceMonthlySavingsData : PerformanceMonthlyUnitData +{ + public double Savings { get; set; } + public double SavingsYTD { get; set; } +} + +public class YearMonth +{ + public int FiscalYear { get; set; } + public int CalendarYear { get; set; } + + public DateTime FiscalYearMonth { get; set; } + public DateTime CalendarYearMonth { get; set; } + + public int FiscalYearID; + public int FiscalMonthID; +} + +public class TrackingYearMonth : YearMonth +{ + public bool IsAfterEffectiveDate { get; set; } + public bool IsBeforeTrackingDate { get; set; } + public bool IsCurrentMonth { get; set; } + public bool IsTrackedMonth { get; set; } +} + +public interface IPerformanceTrackingMonth +{ + TrackingYearMonth Month { get; set; } + double RampUp { get; set; } + double GoalUnits { get; set; } + double GoalUnitsYTD { get; set; } + double CommittedUnits { get; } + double CommittedUnitsYTD { get; set; } + double GoalUnitsOverall { get; set; } + double BaselineUnitsOverall { get; set; } + double BaselineStatsOverall { get; set; } + double TrackingUnitsOverall { get; set; } + double TrackingStatsOverall { get; set; } + PerformanceMonthlyUnitData BaselineMonthlyUnitData { get; set; } + PerformanceMonthlyUnitData TrackingMonthlyUnitData { get; set; } + PerformanceMonthlySavingsData GoalSavings { get; set; } + PerformanceMonthlySavingsData CommittedSavings { get; set; } + PerformanceMonthlySavingsData ActualSavings { get; set; } + double GoalUnitVariance { get; } + double ActualUnitVariance { get; } + double CommittedUnitVariance { get; } + double CommittedRate { get; } +} + +public class PerformanceTrackingMonth : IPerformanceTrackingMonth +{ + public TrackingYearMonth Month { get; set; } + public PerformanceMonthlyUnitData BaselineMonthlyUnitData { get; set; } + public PerformanceMonthlyUnitData TrackingMonthlyUnitData { get; set; } + public PerformanceMonthlySavingsData GoalSavings { get; set; } + public PerformanceMonthlySavingsData CommittedSavings { get; set; } + public PerformanceMonthlySavingsData ActualSavings { get; set; } + public double RampUp { get; set; } + public double BaselineUnitsOverall { get; set; } + public double BaselineStatsOverall { get; set; } + public double TrackingUnitsOverall { get; set; } + public double TrackingStatsOverall { get; set; } + public double GoalUnits { get; set; } + public double GoalUnitsYTD { get; set; } + public double GoalUnitsOverall { get; set; } + public double GoalUnitVariance { get; set; } + public double ActualUnitVariance { get; set; } + public double CommittedStats { get; set; } + public double CommittedUnits { get; set; } + public double CommittedUnitsYTD { get; set; } + public double CommittedUnitVariance { get; set; } + public double CommittedRate { get; set; } +} + +public class PerformanceTrackingItem +{ + public int GroupID { get; set; } + public string GroupName { get; set; } + + public IEnumerable MonthlyTrackingData { get; set; } +} \ No newline at end of file diff --git a/Evaluate QVI Bubble Chart.linq b/Evaluate QVI Bubble Chart.linq new file mode 100644 index 0000000..d842620 --- /dev/null +++ b/Evaluate QVI Bubble Chart.linq @@ -0,0 +1,55 @@ + + + bd4e97c5-84e7-4c61-80ca-8d53d7876af2 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + + +var config = (from c in Configurations where c.FiscalYearID == 2020 select c).First(); +var opps = (from OBJ in QVILineItemOpportunities + join qve in QualityVariationEvents on OBJ.QualityVariationEventID equals qve.QualityVariationEventID + where OBJ.ConfigurationGUID == config.ConfigurationGUID + && !OBJ.IsHidden + select new + { + OBJ.OpportunityGUID, + OBJ.InitiativeGUID, + OBJ.Savings, + // OBJ.DateModified, + // OBJ.DateCreated, + // OBJ.ConfigurationGUID, + // OBJ.IsHidden, + OBJ.TotalCasesWithQVI, + OBJ.TotalPatientDaysWithQVI, + OBJ.TotalCostWithQVI, + OBJ.NetRevenueWithQVI, + OBJ.BreakdownName, + OBJ.BreakdownID, + OBJ.CommittedSavingsLevel, + OBJ.TotalCases, + OBJ.Note, + OBJ.QualityVariationEventID, + QualityVariationEventName = qve.Name, + QualityVariationEventCategory = qve.Category, + qve.QVILineItemID, + QVILineItemName = qve.Name, + QVIName = qve.Category, + qve.SortOrder, + qve.ClinicalIndicatorID + }).ToList(); +opps +.GroupBy(p => p.QualityVariationEventCategory, +(category, qvi) => new +{ + Name = category, + Savings = qvi.Sum(x => x.Savings), + Cases = qvi.Sum(x => x.TotalCasesWithQVI), + SavingsMaxPotential = qvi.WeightedAverage(x => x.Savings.DivideBy(x.TotalCasesWithQVI), w => w.TotalCasesWithQVI), + QVISubItems = qvi.ToList() +}) +.OrderByDescending(p => p.Cases) +.ThenByDescending(p => p.Savings) +.Dump(); \ No newline at end of file diff --git a/FPES Encounter Summary analysis.linq b/FPES Encounter Summary analysis.linq new file mode 100644 index 0000000..8a1fdde --- /dev/null +++ b/FPES Encounter Summary analysis.linq @@ -0,0 +1,34 @@ + + + bd4e97c5-84e7-4c61-80ca-8d53d7876af2 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + + +var startDate = new DateTime(2019, 1, 1); +var endDate = new DateTime(2020, 1, 1); +var months = Enumerable.Range(1, 12).Select(i => new { month = i }).ToList(); +var data = (from fpes in FactPatientEncounterSummaries + join ctf in CaseTypeFamilies on fpes.MSDRGCaseTypeFamilyID equals ctf.CaseTypeFamilyID + where fpes.DischargeDateTime >= startDate && fpes.DischargeDateTime < endDate + && fpes.MSDRGCaseTypeFamilyID != 0 + group fpes by new { DischargeMonth = fpes.DischargeDateTime.Month, ctf.CaseTypeFamilyID, ctf.Name } into gpes + orderby gpes.Key.CaseTypeFamilyID, gpes.Key.DischargeMonth + select new + { + LevelID = 0, + Month = gpes.Key.DischargeMonth, + gpes.Key.CaseTypeFamilyID, + gpes.Key.Name, + Volume = gpes.Select(g => g.EncounterID).Distinct().Count(), + Revenue = gpes.Sum(g => g.NetRevenue), + TotalCost = gpes.Sum(g => g.TotalCosts) + }).ToList(); +var pes = months.GroupJoin(data, m => m.month, d => d.Month, (m, d) => d.DefaultIfEmpty()).SelectMany(m => m) +.OrderBy(m => m.CaseTypeFamilyID) +.ThenBy(m => m.Month); + +pes.Dump(); \ No newline at end of file diff --git a/FactPatientEncounterSummary Query Exceptions.linq b/FactPatientEncounterSummary Query Exceptions.linq new file mode 100644 index 0000000..c16bf4b --- /dev/null +++ b/FactPatientEncounterSummary Query Exceptions.linq @@ -0,0 +1,411 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.ComponentModel + + +private List SchemasAndTablesToReview = new List(); +private List OrderByStatements = new List(); +private List ColumnsToBeExcluded = new List(); +private List JsonColumnsToBeParsed = new List(); +private static Dictionary WhereClauses = new Dictionary(); +public static int TopRows = int.MaxValue; + +void Main() +{ + SchemasAndTablesToReview.AddRange(new[] + { + new TablesAndColumns("clientdss", new [] { "FactPatientEncounterSummary" }) + }); + WhereClauses.Add("clientdss.FactPatientEncounterSummary", "OBJ.MSDRGCaseTypeFamilyID <> 0 OR OBJ.APRDRGCaseTypeFamilyID <> 0"); + OrderByStatements.AddRange(new[] + { + new OrderByInformation("cci.InitiativeWorkflowHistory", new [] {"FromStep","ToStep"}), + new OrderByInformation("cci.VariationEncounterSavingInfo", new []{"EncounterRecordNumber","PhysicianID"}), + new OrderByInformation("cci.FactOpportunityMetric", new []{"FiscalYearID","FiscalMonthID"}), + new OrderByInformation("cci.FactOpportunitySavings", new []{"FiscalyYearID","FiscalMonthID"}), + new OrderByInformation("clientdss.FactPatientEncounterSummary", new []{"EncounterRecordNumber"}), + new OrderByInformation("dss.DimCaseType", new []{"CaseTypeFamilyID", "CaseTypeId", "Name"}) + }); + ColumnsToBeExcluded.AddRange(new[] + { + new ColumnsToExclude("cci.SystemSetting", new [] {"IsEncrypted"}), + new ColumnsToExclude("cci.Configuration", new [] {"InitiativeIsSimplifiedWorkflow"}), + new ColumnsToExclude("clientdss.FactPatientEncounterSummary", new [] {"MikeQAtest1ID", "CustomJesseValidatingAllOthers", "CustomNewCalculatedSystemFieldasdf"}) + }); + JsonColumnsToBeParsed.AddRange(new[] + { + new JsonColumns("dss.DimCaseType", new [] {"CaseTypeConfigJSON"}) + }); + + var tables = GetTables(); + var tableList = tables.Select(r => r.SchemaTable); + var connections = new ServerInstance[] { + new ServerInstance("D0011-SQL-01.sdt.local","jazz tst Southern Illinois 20190918.1", tableList), + new ServerInstance("D0011-SQL-01.sdt.local", "jazz tst Southern Illinois 20200331.1", tableList) + }.ToList(); + DoTheComparisons(connections, tables); +} + +// Define other methods and classes here + +#region Gather Table Information + +public string GetTableQuery() +{ + var tableSchemas = string.Join(", ", SchemasAndTablesToReview.Select(sattr => $"'{sattr.SchemaName}'")); + var tableList = string.Join("\r\n", SchemasAndTablesToReview.ConvertAll(sattr => + { + if (sattr.TableNames?.Any(cn => cn == "*") ?? true) + { + return $"WHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' THEN 1"; + } + else + { + return $"WHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' AND c.TABLE_NAME IN ({string.Join(", ", sattr.TableNames.Select(cn => $"'{cn}'"))}) THEN 1"; + } + })); + return $@"SELECT c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE +, CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey +FROM INFORMATION_SCHEMA.COLUMNS AS c +LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON tc.TABLE_SCHEMA = c.TABLE_SCHEMA AND tc.TABLE_NAME = c.TABLE_NAME +LEFT OUTER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.TABLE_SCHEMA = tc.TABLE_SCHEMA AND ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME AND ccu.COLUMN_NAME = c.COLUMN_NAME +WHERE c.TABLE_SCHEMA in ({tableSchemas}) +AND (CASE +{tableList} +ELSE 0 +END = 1) +AND c.DATA_TYPE NOT IN ('datetime','uniqueidentifier', 'timestamp') +AND NOT (c.COLUMN_NAME = 'RowID' and CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) = 1) +AND tc.CONSTRAINT_TYPE = 'Primary Key' +ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION"; +} + +public IList
GetTables() +{ + var tableQuery = GetTableQuery(); + return ExecuteQueryDynamic(tableQuery) + .GroupBy(x => new { x.TABLE_SCHEMA, x.TABLE_NAME }, (g, d) => new Table + { + SchemaName = g.TABLE_SCHEMA, + TableName = g.TABLE_NAME, + Columns = d + .Select(y => new Column + { + ColumnName = y.COLUMN_NAME, + DataType = y.DATA_TYPE, + IsPrimaryKey = y.IsPrimaryKey + }), + OrderBy = OrderByStatements?.SingleOrDefault(obs => obs.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.OrderBy, + Exclude = ColumnsToBeExcluded?.SingleOrDefault(ctbe => ctbe.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.ColumnNames ?? new List(), + Json = JsonColumnsToBeParsed?.SingleOrDefault(ctbe => ctbe.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.ColumnNames ?? new List(), + Where = WhereClauses.ContainsKey($"{g.TABLE_SCHEMA}.{g.TABLE_NAME}") ? $"\r\nwhere {WhereClauses[$"{g.TABLE_SCHEMA}.{g.TABLE_NAME}"]}" : "" + }).ToList(); +} + +public class Table +{ + public string SchemaName { get; set; } + public string TableName { get; set; } + public IEnumerable Columns { get; set; } + public IEnumerable OrderBy { get; set; } + public IEnumerable Exclude { get; set; } + public IEnumerable Json { get; set; } + public string Where { get; set; } = ""; + internal string SchemaTable => $"{SchemaName}.{TableName}"; + public string SqlSelect => $"select TOP({TopRows}) \r\n\t{SelectColumns}\r\nfrom {SchemaTable} OBJ{Where}{OrderByStatement}"; + internal string SelectColumns => !Columns?.Any() ?? true ? "*" : string.Join(",\r\n\t", Columns.Where(c => !Exclude.ToList().Contains(c.ColumnName)).Select(c => c.ColumnName)); + internal string OrderByStatement => !OrderBy?.Any() ?? true ? "" : "\r\nOrder By " + string.Join(", ", OrderBy.Select(ob => $"{ob.ColumnName}{(ob.IsDescending ? " DESC" : "")}")); +} + +public class Column +{ + public string ColumnName { get; set; } + public string DataType { get; set; } + public bool IsPrimaryKey { get; set; } +} + +public class OrderBy +{ + public string ColumnName { get; set; } + public bool IsDescending { get; set; } = false; +} + +public class TablesAndColumns +{ + public string SchemaName { get; set; } + public IEnumerable TableNames { get; set; } + public TablesAndColumns(string schemaName, IEnumerable tables) + { + SchemaName = schemaName; + TableNames = tables; + } +} + +public class OrderByInformation +{ + public string TableName { get; set; } + public IEnumerable OrderBy { get; set; } + public OrderByInformation(string tableName, IEnumerable columns) + { + TableName = tableName; + OrderBy = columns.Select(c => new OrderBy + { + ColumnName = c.StartsWith("D|") ? c.Substring(2) : c, + IsDescending = c.StartsWith("D|") + }); + } +} + +public class ColumnsToExclude +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public ColumnsToExclude(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +public class JsonColumns +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public JsonColumns(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +#endregion + +#region Do the comparisons + +public void DoTheComparisons(IEnumerable connections, IEnumerable
tables) +{ + foreach (var table in tables) + { + var sql = table.SqlSelect; + var dataLegacy = GetData(connections.First(), sql); + var dataUpdate = GetData(connections.Last(), sql); + + var legacy = dataLegacy.Rows; + var update = dataUpdate.Rows; + var idxCount = legacy.Count; + var compare = new List(); + var jsonColumns = tables.SingleOrDefault(t => t.SchemaTable == table.TableName)?.Json.ToList(); + foreach (var row in Enumerable.Range(0, idxCount)) + { + var r = legacy[row]; + if (row < update.Count) + { + var u = update[row]; + var rJson = JsonConvert.SerializeObject(r.ItemArray); + var uJson = JsonConvert.SerializeObject(u.ItemArray); + if (rJson != uJson) + { + if (jsonColumns == null) + { + compare.Add(new CompareSet(r, u)); + } + else + { + compare.Add(new CompareSet(r, u, jsonColumns)); + } + } + } + else + { + if (jsonColumns == null) + { + compare.Add(new CompareSet(r, null)); + } + else + { + compare.Add(new CompareSet(r, null, jsonColumns)); + } + } + } + if (compare.Any()) + { + compare.Dump(table.TableName, 3); + } + else + { + "No differences found in data".Dump($"{table.TableName} ({dataLegacy.Rows.Count} rows)"); + } + } +} + +public class ServerInstance +{ + public string Server { get; set; } + public string Database { get; set; } + public IEnumerable TableNames { get; set; } + public ServerInstance(string server, string database, IEnumerable tableNames) + { + Server = server; + Database = database; + TableNames = tableNames; + } +} + +public DataTable GetData(ServerInstance serverInstance, string sql) +{ + var server = serverInstance.Server; + var database = serverInstance.Database; + var connStr = $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;"; + using (var conn = new SqlConnection(connStr)) + { + var datatable = new DataTable(); + var adapter = new SqlDataAdapter(sql, conn); + try + { + adapter.Fill(datatable); + } + catch (Exception ex) + { + sql.Dump(nameof(sql)); + throw; + } + var tableNames = serverInstance.TableNames; + var idx = 0; + foreach (var tableName in tableNames) + { + datatable.TableName = tableName; + idx += 1; + } + return datatable; + } +} + +public class CompareSet +{ + internal IList ColumnNames { get; set; } + internal IList Legacy { get; set; } + internal IList Update { get; set; } + public IList Rows { get; set; } + internal IList JsonColumns { get; set; } + public CompareSet(DataRow right, DataRow left) + { + ColumnNames = right.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + Legacy = right.ItemArray.ToList(); + Update = left?.ItemArray.ToList(); + Rows = ColumnNames.Select((c, i) => new Row(c, Legacy[i], Update?[i])).ToList(); + } + public CompareSet(DataRow right, DataRow left, IList jsonColumns) + { + ColumnNames = right.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + Legacy = right.ItemArray.ToList(); + Update = left?.ItemArray.ToList(); + JsonColumns = jsonColumns; + Rows = ColumnNames.Select((c, i) => new Row(c, Legacy[i], Update?[i], JsonColumns.Contains(c, StringComparer.CurrentCultureIgnoreCase))).ToList(); + } + +} + +public class Row +{ + public string Column; + public bool IsJson; + public object Left; + public object Right; + + public Row(string column, object left, object right) + { + Column = column; + Left = left; + Right = right; + } + + public Row(string column, object left, object right, bool isJson) + : this(column, left, right) + { + IsJson = isJson; + if (!isJson) return; + Left = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(left.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + if (right == null) return; + Right = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(right.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + } + + object ToDump() => new + { + Column = Left.Equals(Right ?? "") ? (object)Column : new XElement("LINQPad.HTML", new XElement("div", new XAttribute("style", "background-color:lightyellow;color:black"), Column)), + Left, + Right + }; +} + +#endregion \ No newline at end of file diff --git a/Find string in table data.linq b/Find string in table data.linq new file mode 100644 index 0000000..26d19f6 --- /dev/null +++ b/Find string in table data.linq @@ -0,0 +1,98 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var searchFor = "Vice President"; + var sql = new List(); + foreach (var table in Mapping.GetTables()) + { + var columns = from dm in table.RowType.DataMembers + where dm.DbType != null && dm.DbType.Contains("Varchar") + select new { dm.Name, dm.DbType, dm.Type, dm.MappedName, dm.IsPrimaryKey }; + if (!columns.Any()) continue; + //columns.Dump(table.TableName); + sql.AddRange(columns.Select(x => $@"SELECT '{table.TableName}.{x.Name}' what, LEFT({table.TableName}.[{x.Name}], 3630) has + FROM {table.TableName} (NOLOCK) + WHERE {table.TableName}.[{x.Name}] LIKE '%{searchFor}%'")); + } + sql.ForEach(query => + { + try + { + var result = this.ExecuteQuery(query).ToList(); + if (result.Any()) + { + result.Select(r => r.has).Dump(result.First().what); + } + } + catch (Exception ex) + { + query.Dump(ex.Message); + } + }); +} + +public class Answer +{ + public string what { get; set; } + public string has { get; set; } +} \ No newline at end of file diff --git a/FiscalMonthResolver/Test FiscalMonthResolver.linq b/FiscalMonthResolver/Test FiscalMonthResolver.linq new file mode 100644 index 0000000..0e9e07f --- /dev/null +++ b/FiscalMonthResolver/Test FiscalMonthResolver.linq @@ -0,0 +1,184 @@ + + + eae63890-d1e5-4142-8086-9d954a38c63c + true + D0011-SQL-01.sdt.local + jazz tst Edward Elmhurst 20210127.1 + true + + System.Collections.ObjectModel + + +void Main() +{ + var fmr = new FiscalMonthResolver(from fm in DimFiscalMonths + select new FiscalMonth + { + MemberGUID = fm.MemberGUID, + FiscalMonthID = fm.FiscalMonthID, + SortOrder = fm.SortOrder, + FiscalMonthCode = int.Parse(fm.FiscalMonthCode), + Name = fm.Name, + Abbreviation = fm.Abbreviation, + DaysInMonth = fm.DaysInMonth, + YTDDaysInMonth = fm.YTDDaysInMonth, + QuarterID = fm.QuarterID, + MonthColumnName = fm.MonthColumnName, + TransactionID = fm.TransactionID, + DaysInLeapYearMonth = fm.DaysInLeapYearMonth, + YTDDaysInLeapYearMonth = fm.YTDDaysInLeapYearMonth, + IsReal = fm.IsReal + }); + + var config = new Configuration(fmr); + var fiscalMonths = fmr.AllFiscalMonths; + var startDate = new DateTime(2020, 1, 1); + var endDate = startDate.AddYears(1).AddDays(-1); + config.GetYearMonths(startDate, endDate).Dump(); + + startDate = config.GetFiscalYearStartDate(); + endDate = config.GetFiscalYearEndDate(); + config.GetYearMonths(startDate, endDate).Dump(); + fiscalMonths.Where(fm => fm.IsReal).Dump(); +} + +// Define other methods and classes here + +public class Configuration +{ + public int FiscalYearID = 2020; + public FiscalMonthResolver FiscalMonthResolver; + + public Configuration(FiscalMonthResolver fmr) + { + FiscalMonthResolver = fmr; + } + + public DateTime GetFiscalYearStartDate() + { + return GetFiscalYearEndDate().AddYears(-1).AddDays(1); + } + + public DateTime GetFiscalYearEndDate() + { + var lastFiscalMonth = FiscalMonthResolver.LastFiscalMonth.FiscalMonthID; + return new DateTime(FiscalYearID, lastFiscalMonth, DateTime.DaysInMonth(FiscalYearID, lastFiscalMonth)); + } + + public IList GetYearMonths(DateTime startDate, DateTime endDate) + { + var ym = new List(); + var currentMonth = startDate; + $"\r\nCurrent: {currentMonth:d} - End: {endDate:d}".Dump(); + while (currentMonth <= endDate) + { + var fiscalMonth = FiscalMonthResolver.ConvertToFiscalYearMonth(currentMonth); + fiscalMonth.Dump(); + ym.Add(new YearMonth(fiscalMonth.Year, currentMonth.Year, + FiscalMonthResolver.GetByFiscalMonthId(currentMonth.Month))); + currentMonth = currentMonth.AddMonths(1); + } + return ym; + } +} + +public interface IFiscalMonthResolver + +{ + FiscalMonth FirstFiscalMonth { get; } + + FiscalMonth LastFiscalMonth { get; } + + FiscalMonth GetByFiscalMonthId(int fiscalMonthId); + + FiscalMonth GetByFiscalMonthSortOrder(int sortOrder); + + List AllFiscalMonths { get; } +} + +public class FiscalMonthResolver : IFiscalMonthResolver +{ + public FiscalMonthResolver(IEnumerable fiscalMonths) + { + AllFiscalMonths = fiscalMonths.ToList(); + } + + public FiscalMonth FirstFiscalMonth => GetByFiscalMonthSortOrder(1); + + public FiscalMonth LastFiscalMonth => GetByFiscalMonthSortOrder(12); + + public List AllFiscalMonths { get; set; } + + public FiscalMonth GetByFiscalMonthId(int fiscalMonthId) + { + return AllFiscalMonths.FirstOrDefault(afm => afm.FiscalMonthID == fiscalMonthId); + } + + public FiscalMonth GetByFiscalMonthSortOrder(int sortOrder) + { + return AllFiscalMonths.FirstOrDefault(afm => afm.SortOrder == sortOrder); + } + + public DateTime ConvertToFiscalYearMonth(DateTime calendarYearMonth) + { + var fiscalYearID = calendarYearMonth.Month <= LastFiscalMonth.FiscalMonthID + ? calendarYearMonth.Year + : calendarYearMonth.Year + 1; + return new DateTime(fiscalYearID, calendarYearMonth.Month, 1); + } +} + +public class FiscalMonth +{ + internal Guid MemberGUID { get; set; } + public byte FiscalMonthID { get; set; } + public byte SortOrder { get; set; } + public int FiscalMonthCode { get; set; } + public String Name { get; set; } + public String Abbreviation { get; set; } + public Int32 DaysInMonth { get; set; } + public Int32 YTDDaysInMonth { get; set; } + public byte QuarterID { get; set; } + public String MonthColumnName { get; set; } + internal String Version { get; set; } + internal Guid HistoryItemGUID { get; set; } + internal Int32 TransactionID { get; set; } + public Int32 DaysInLeapYearMonth { get; set; } + public Int32 YTDDaysInLeapYearMonth { get; set; } + public Boolean IsReal { get; set; } + +} + +public class YearMonth +{ + public readonly int FiscalYear; + public readonly int CalendarYear; + + internal readonly FiscalMonth FiscalMonth; + + public readonly DateTime FiscalYearMonth; + + public readonly DateTime CalendarYearMonth; + + #region Helper Properties to corelate to database column names + + public int FiscalYearID => FiscalYear; + + /// + /// This is calendar month and FiscalMonth.SortOrder is the real FiscalMonth + /// we put it here so that we don't frikin confuse ourself between fiscalmonth and calendarmonth :x + /// + public int FiscalMonthID => FiscalMonth.FiscalMonthID; + + #endregion + + internal YearMonth(int fiscalYear, int calendarYear, FiscalMonth fiscalMonth) + { + FiscalYear = fiscalYear; + CalendarYear = calendarYear; + FiscalMonth = fiscalMonth; + + FiscalYearMonth = new DateTime(fiscalYear, fiscalMonth.SortOrder, 1); + CalendarYearMonth = new DateTime(calendarYear, fiscalMonth.FiscalMonthID, 1); + } +} \ No newline at end of file diff --git a/Fluent Assertion IAssertionRule Test.linq b/Fluent Assertion IAssertionRule Test.linq new file mode 100644 index 0000000..7d12cab --- /dev/null +++ b/Fluent Assertion IAssertionRule Test.linq @@ -0,0 +1,114 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + FluentAssertions + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + FluentAssertions.Equivalency + FluentAssertions.Execution + FluentAssertions + + +void Main() +{ + var lt = LoginType.Something; + Action act1 = () => + { + var ltDto = LoginTypeDto.Something; + ltDto.Should().BeEquivalentTo(lt, options => options.Using(new LoginTypeRule())); + }; + Action act2 = () => + { + var ltDto = LoginTypeDto.SomethingElse; + ltDto.Should().BeEquivalentTo(lt, options => options.Using(new LoginTypeRule())); + }; + act1.Should().NotThrow(); + act2.Should().Throw(); +} + +// Define other methods and classes here +public class LoginTypeRule : IAssertionRule +{ + public bool AssertEquality(IEquivalencyValidationContext context) + { + var subjectValue = GetValueForEnum(context.Subject); + var expectationValue = GetValueForEnum(context.Expectation); + + if (subjectValue == null || expectationValue == null) + { + // rule not applicable + return false; + } + + Execute.Assertion + .BecauseOf(context.Because, context.BecauseArgs) + .ForCondition(subjectValue == expectationValue) + .FailWith("Expected {context:string} to be {0}{reason}, but found {1}", + context.Subject, context.Expectation); + + // equality assertion handled + return true; + } + + private int? GetValueForEnum(object enumValue) + { + if (enumValue is LoginType || enumValue is LoginTypeDto) + { + return (int)enumValue; + } + return null; + } + +} + +enum LoginType { Something, SomethingElse, Other }; + +enum LoginTypeDto { Something, SomethingElse, Other } + diff --git a/Func Test.linq b/Func Test.linq new file mode 100644 index 0000000..ac69aff --- /dev/null +++ b/Func Test.linq @@ -0,0 +1,70 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +//Func f = (x => x + x); +var bb = new bool[] { false, true, true, false }; +var xx = new decimal[] { 1.0m, 0.0m, 3.0m, 4.0m }; +Func f = ((x,month) => bb[x] +? xx[x] == 0.0m + ? 1.0 : (double)month +: (double)month); +f(0,xx[3]).Dump(); +f(1,xx[2]).Dump(); \ No newline at end of file diff --git a/Get Report Parms.linq b/Get Report Parms.linq new file mode 100644 index 0000000..5b4c02d --- /dev/null +++ b/Get Report Parms.linq @@ -0,0 +1,83 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + jazz tst StrataSphere 20191104.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var doc = new XmlDocument(); + var info = + from r in REReports + join p in REDSCubeReportParameters on r.ReportGUID equals p.ReportGUID into rdscrp + from p in rdscrp.DefaultIfEmpty() + join rp in REClientReportParameters on r.ReportGUID equals rp.ReportGUID into rcrp + from rp in rcrp.DefaultIfEmpty() + where r.Name.Contains("B-25227") + //where new[] { "B-25227" }.Contains(r.Name) + select new { Parameters = p == null ? rp.ParameterXML : p.ParameterXML, r }; + var test = info.ToList() + .ConvertAll(i => + { + doc.LoadXml(i.Parameters); + return new { i.r.Name, parameter = JsonConvert.SerializeXmlNode(doc, Newtonsoft.Json.Formatting.Indented) }; + }); + test.Dump(); +} + +// Define other methods and classes here diff --git a/HackWeek AWS/AWS SDK Basics.linq b/HackWeek AWS/AWS SDK Basics.linq new file mode 100644 index 0000000..4e1a110 --- /dev/null +++ b/HackWeek AWS/AWS SDK Basics.linq @@ -0,0 +1,200 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.Glue + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Amazon.Glue + Amazon.Glue.Model + System.Threading.Tasks + + +void Main() +{ + var accessKeyID = Util.GetPassword("aws.sdt-tlamb.accessid"); + var secretKey = Util.GetPassword("aws.sdt-tlamb.secretid"); + var bucketName = "sdt-glue-hackweek"; + var crawlerName = "client1_input_icd10dx"; + + var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1); + var glueclient = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1); + + //UploadICDFiles(client, bucketName); + //ListBucket(client, bucketName).Dump("S3 Buckets"); + ListCrawlers(glueclient).Crawlers.Select(c => new + { + c.Name, + c.DatabaseName, + c.LastCrawl.Status, + c.LastCrawl.ErrorMessage, + c.Description, + c.Targets.S3Targets + }).Dump("Crawlers"); + /* + //RunCrawler(glueclient, crawlerName).Dump(); + glueclient.GetDatabases(new GetDatabasesRequest{}).DatabaseList.Dump("Database"); + glueclient.GetCrawler(new GetCrawlerRequest { Name = crawlerName}).Crawler.Dump("Crawler"); + glueclient.GetTables(new GetTablesRequest{DatabaseName = "glue-hackweek-icd"}).TableList.Dump("glue hackweek icd tables"); + */ +} + +// Define other methods and classes here + +void UploadICDFiles(AmazonS3Client client, string bucketName) +{ + var regex = new Regex("wfu_icd(10|9)_(dx|px)_(\\d*)", RegexOptions.IgnoreCase | RegexOptions.Singleline); + var sourcePath = @"S:\Development\Cube Killers\Deidentified DI Import Files\Wake - Deidentified"; + var sourceFiles = "wfu_icd*.psv"; + var files = System.IO.Directory.GetFiles(sourcePath, sourceFiles).OrderBy(f => f); + files + //.Where(f => f.Contains("10_dx")) + //.Take(1) + .ToList().ForEach(f => + { + var fileName = Path.GetFileNameWithoutExtension(f); + var subdir = regex.Replace(fileName, "icd/icd$1/$2"); + var key = regex.Replace(fileName, "icd$1$2"); + TransferToBucketAsync(client, bucketName, subdir, key, f).Wait();//.Dump(); + }); +} + +ListObjectsResponse ListBucket(AmazonS3Client client, string bucketName) +{ + var request = new Amazon.S3.Model.ListObjectsRequest(); + return client.ListObjects(bucketName); +} + +ListObjectsResponse ListBucket(string accessKeyID, string secretKey, string bucketName) +{ + using (var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + return ListBucket(client, bucketName); + } +} + +static async Task TransferToBucketAsync(AmazonS3Client client, string bucketName, string subdirName, string keyName, string fileName) +{ + new { keyName, fileName }.Dump(); + var utility = new TransferUtility(client); + var request = new TransferUtilityUploadRequest + { + BucketName = $"{bucketName}{(!string.IsNullOrEmpty(subdirName) ? @"/" + subdirName : "")}", + Key = keyName, + ContentType = "text/plain" + }; + request.FilePath = fileName; + await utility.UploadAsync(request); +} + +static async Task UploadToBucketAsync(AmazonS3Client client, string bucketName, string keyName, string fileName) +{ + new { keyName, fileName }.Dump(); + var request = new Amazon.S3.Model.PutObjectRequest + { + BucketName = bucketName, + Key = keyName, + ContentBody = File.ReadAllText(fileName), + ContentType = "text/plain" + }; + request.FilePath = fileName; + return await client.PutObjectAsync(request); +} +PutObjectResponse UploadToBucket(AmazonS3Client client, string bucketName, string keyName, string fileName) +{ + new { keyName, fileName }.Dump(); + var result = UploadToBucketAsync(client, bucketName, keyName, fileName); + result.Wait(); + return result.Result; +} + +PutObjectResponse UploadToBucket(string accessKeyID, string secretKey, string bucketName, string keyName, string fileName) +{ + using (var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + return UploadToBucket(client, bucketName, keyName, fileName); + } +} + +GetCrawlersResponse ListCrawlers(AmazonGlueClient client) +{ + return client.GetCrawlers(new GetCrawlersRequest()); +} + +GetCrawlersResponse ListCrawlers(string accessKeyID, string secretKey) +{ + + using (var client = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + var crawlerRequest = new GetCrawlersRequest(); + return client.GetCrawlers(crawlerRequest); + } +} + +StartCrawlerResponse RunCrawler(AmazonGlueClient client, string crawlerName) +{ + var crawler = new StartCrawlerRequest + { + Name = crawlerName + }; + return client.StartCrawler(crawler); +} + +StartCrawlerResponse RunCrawler(string accessKeyID, string secretKey, string crawlerName) +{ + + using (var client = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + var crawler = new StartCrawlerRequest + { + Name = crawlerName + }; + return client.StartCrawler(crawler); + } +} diff --git a/HackWeek AWS/HackWeek AWS Glue Bucket to Crawlers.linq b/HackWeek AWS/HackWeek AWS Glue Bucket to Crawlers.linq new file mode 100644 index 0000000..df27183 --- /dev/null +++ b/HackWeek AWS/HackWeek AWS Glue Bucket to Crawlers.linq @@ -0,0 +1,142 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.Glue + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Amazon.Glue + Amazon.Glue.Model + System.Threading.Tasks + + +//#define TRACE + +void Main() +{ + var accessKeyID = Util.GetPassword("aws.sdt-tlamb.accessid"); + var secretKey = Util.GetPassword("aws.sdt-tlamb.secretid"); + var bucketName = "sdt-glue-hackweek"; + + var s3 = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1); + + var s3Objects = bucketName.AWSListBucket(s3).S3Objects + .Where(so => so.Key.StartsWith("wfu/")); + s3Objects.Dump("S3 Objects"); + + //var crawlerName = "client1_input_icd10dx"; + + var glue = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1); + var dbs = glue.GetDatabases(new GetDatabasesRequest()).DatabaseList.Select(dl => dl.Name); + var myDBName = "glue-hackweek-thom"; + if (dbs.Contains(myDBName)) + { + glue.DeleteDatabase(new DeleteDatabaseRequest { Name = myDBName }); + } + glue.CreateDatabase(new CreateDatabaseRequest { DatabaseInput = new DatabaseInput { Name = myDBName, Description = "Thom's Glue Hackweek DB" } }); + var crawlers = glue.ListCrawlers(new ListCrawlersRequest()).CrawlerNames; + var tasks = new List>(); + crawlers.Where(c => c.StartsWith("wfu_")).ToList() + .ForEach(c => + { + try + { + glue.DeleteCrawler(new DeleteCrawlerRequest { Name = c }); + } + catch (EntityNotFoundException ex) + { + ex.Message.Dump(); + } + }); + crawlers = glue.ListCrawlers(new ListCrawlersRequest()).CrawlerNames; + + var tags = new[] { new { key = "environment", value = "hackweek" } }.ToDictionary(dl => dl.key, dl => dl.value); + var newCrawlers = s3Objects.ToList() + .ConvertAll(o => new CreateCrawlerRequest + { + Classifiers = new[] { "client1-input-psv" }.ToList(), + Configuration = @"{""Version"":1.0,""CrawlerOutput"":{""Partitions"":{""AddOrUpdateBehavior"":""InheritFromTable""}}}", + DatabaseName = myDBName, + Name = string.Join("_", o.Key.Split('/').TakeAllButLast()), + Role = "hackday-glue-role-team2", + SchemaChangePolicy = new SchemaChangePolicy + { + DeleteBehavior = new DeleteBehavior("LOG"), + UpdateBehavior = new UpdateBehavior("UPDATE_IN_DATABASE") + }, + TablePrefix = string.Join("_", o.Key.Split('/').TakeAllButLast().TakeAllButLast()) + "_", + Tags = tags, + Targets = new CrawlerTargets + { + S3Targets = new List { + new S3Target { Path = $"s3://{o.BucketName}/{string.Join("/", o.Key.Split('/').TakeAllButLast())}" } + } + } + }).OrderBy(o => o.Name).ToList(); + newCrawlers.Dump("New Crawlers"); + newCrawlers.ForEach(c => + { + try + { + tasks.Add(glue.CreateCrawlerAsync(c, new CancellationToken())); + } + catch (AmazonGlueException ex) + { + ex.Dump($"Glue Exception {c.Name}"); + } + }); + while (tasks.Any(t => !t.IsCompleted)) + { + } + var runtasks = new List>(); + newCrawlers.ForEach(c => runtasks.Add(glue.StartCrawlerAsync(new StartCrawlerRequest { Name = c.Name }))); + runtasks.Dump("Run Tasks"); +} + +// Define other methods and classes here \ No newline at end of file diff --git a/HackWeek AWS/HackWeek AWS Glue Create Crawler on the fly.linq b/HackWeek AWS/HackWeek AWS Glue Create Crawler on the fly.linq new file mode 100644 index 0000000..f54dcdd --- /dev/null +++ b/HackWeek AWS/HackWeek AWS Glue Create Crawler on the fly.linq @@ -0,0 +1,77 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.Glue + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Amazon.Glue + Amazon.Glue.Model + System.Threading.Tasks + + +void Main() +{ + var accessKeyID = Util.GetPassword("aws.sdt-tlamb.accessid"); + var secretKey = Util.GetPassword("aws.sdt-tlamb.secretid"); + var crawlerName = "client1_input_icd10dx"; + + var client = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1); + var regex = new Regex("(icd_?)(10)"); + + var crawler = client.GetCrawler(new GetCrawlerRequest { Name = crawlerName }).Crawler; + var newCrawler = JsonConvert.DeserializeObject(regex.Replace(JsonConvert.SerializeObject(crawler), "${1}9")); + //newCrawler.LastCrawl = null; + crawler.Dump("Crawler"); + newCrawler.Dump("New Crawler"); + var result = client.CreateCrawler(newCrawler); + result.Dump(); +} + +// Define other methods and classes here diff --git a/HackWeek AWS/HackWeek AWS Glue List Bucket.linq b/HackWeek AWS/HackWeek AWS Glue List Bucket.linq new file mode 100644 index 0000000..86c0c23 --- /dev/null +++ b/HackWeek AWS/HackWeek AWS Glue List Bucket.linq @@ -0,0 +1,70 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.Glue + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Amazon.Glue + Amazon.Glue.Model + System.Threading.Tasks + + +void Main() +{ + var accessKeyID = Util.GetPassword("aws.sdt-tlamb.accessid"); + var secretKey = Util.GetPassword("aws.sdt-tlamb.secretid"); + var bucketName = "sdt-glue-hackweek"; + + var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1); + + bucketName.AWSListBucket(client).S3Objects.Dump("S3 Objects"); +} + +// Define other methods and classes here diff --git a/HackWeek AWS/HackWeek AWS Glue List Crawlers.linq b/HackWeek AWS/HackWeek AWS Glue List Crawlers.linq new file mode 100644 index 0000000..8ab550d --- /dev/null +++ b/HackWeek AWS/HackWeek AWS Glue List Crawlers.linq @@ -0,0 +1,201 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.Glue + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Amazon.Glue + Amazon.Glue.Model + System.Threading.Tasks + + +void Main() +{ + var accessKeyID = Util.GetPassword("aws.sdt-tlamb.accessid"); + var secretKey = Util.GetPassword("aws.sdt-tlamb.secretid"); + var bucketName = "sdt-glue-hackweek"; + var crawlerName = "client1_input_icd10dx"; + + var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1); + var glueclient = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1); + + //UploadICDFiles(client, bucketName); + //ListBucket(client, bucketName).Dump("S3 Buckets"); + ListCrawlers(glueclient).Crawlers.Select(c => new + { + c.Name, + c.DatabaseName, + c.LastCrawl.Status, + c.LastCrawl.ErrorMessage, + c.Description, + c.Targets.S3Targets + }).Dump("Crawlers"); + /* + //RunCrawler(glueclient, crawlerName).Dump(); + glueclient.GetDatabases(new GetDatabasesRequest{}).DatabaseList.Dump("Database"); + glueclient.GetCrawler(new GetCrawlerRequest { Name = crawlerName}).Crawler.Dump("Crawler"); + glueclient.GetTables(new GetTablesRequest{DatabaseName = "glue-hackweek-icd"}).TableList.Dump("glue hackweek icd tables"); + */ +} + +// Define other methods and classes here + +void UploadICDFiles(AmazonS3Client client, string bucketName) +{ + var regex = new Regex("wfu_icd(10|9)_(dx|px)_(\\d*)", RegexOptions.IgnoreCase | RegexOptions.Singleline); + var sourcePath = @"S:\Development\Cube Killers\Deidentified DI Import Files\Wake - Deidentified"; + var sourceFiles = "wfu_icd*.psv"; + var files = System.IO.Directory.GetFiles(sourcePath, sourceFiles).OrderBy(f => f); + files + //.Where(f => f.Contains("10_dx")) + //.Take(1) + .ToList().ForEach(f => + { + var fileName = Path.GetFileNameWithoutExtension(f); + var subdir = regex.Replace(fileName, "icd/icd$1/$2"); + var key = regex.Replace(fileName, "icd$1$2"); + TransferToBucketAsync(client, bucketName, subdir, key, f).Wait();//.Dump(); + }); +} + +ListObjectsResponse ListBucket(AmazonS3Client client, string bucketName) +{ + var request = new Amazon.S3.Model.ListObjectsRequest(); + return client.ListObjects(bucketName); +} + +ListObjectsResponse ListBucket(string accessKeyID, string secretKey, string bucketName) +{ + using (var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + return ListBucket(client, bucketName); + } +} + +static async Task TransferToBucketAsync(AmazonS3Client client, string bucketName, string subdirName, string keyName, string fileName) +{ + new { keyName, fileName }.Dump(); + var utility = new TransferUtility(client); + var request = new TransferUtilityUploadRequest + { + BucketName = $"{bucketName}{(!string.IsNullOrEmpty(subdirName) ? @"/" + subdirName : "")}", + Key = keyName, + ContentType = "text/plain" + }; + request.FilePath = fileName; + await utility.UploadAsync(request); +} + +static async Task UploadToBucketAsync(AmazonS3Client client, string bucketName, string keyName, string fileName) +{ + new { keyName, fileName }.Dump(); + var request = new Amazon.S3.Model.PutObjectRequest + { + BucketName = bucketName, + Key = keyName, + ContentBody = File.ReadAllText(fileName), + ContentType = "text/plain" + }; + request.FilePath = fileName; + return await client.PutObjectAsync(request); +} + +PutObjectResponse UploadToBucket(AmazonS3Client client, string bucketName, string keyName, string fileName) +{ + new { keyName, fileName }.Dump(); + var result = UploadToBucketAsync(client, bucketName, keyName, fileName); + result.Wait(); + return result.Result; +} + +PutObjectResponse UploadToBucket(string accessKeyID, string secretKey, string bucketName, string keyName, string fileName) +{ + using (var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + return UploadToBucket(client, bucketName, keyName, fileName); + } +} + +GetCrawlersResponse ListCrawlers(AmazonGlueClient client) +{ + return client.GetCrawlers(new GetCrawlersRequest()); +} + +GetCrawlersResponse ListCrawlers(string accessKeyID, string secretKey) +{ + + using (var client = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + var crawlerRequest = new GetCrawlersRequest(); + return client.GetCrawlers(crawlerRequest); + } +} + +StartCrawlerResponse RunCrawler(AmazonGlueClient client, string crawlerName) +{ + var crawler = new StartCrawlerRequest + { + Name = crawlerName + }; + return client.StartCrawler(crawler); +} + +StartCrawlerResponse RunCrawler(string accessKeyID, string secretKey, string crawlerName) +{ + + using (var client = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1)) + { + var crawler = new StartCrawlerRequest + { + Name = crawlerName + }; + return client.StartCrawler(crawler); + } +} diff --git a/HackWeek AWS/HackWeek AWS Glue Run Crawlers.linq b/HackWeek AWS/HackWeek AWS Glue Run Crawlers.linq new file mode 100644 index 0000000..fd580ee --- /dev/null +++ b/HackWeek AWS/HackWeek AWS Glue Run Crawlers.linq @@ -0,0 +1,70 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.Glue + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Amazon.Glue + Amazon.Glue.Model + System.Threading.Tasks + + +void Main() +{ + var accessKeyID = Util.GetPassword("aws.sdt-tlamb.accessid"); + var secretKey = Util.GetPassword("aws.sdt-tlamb.secretid"); + var crawlerNames = new[] { "client1_input_icd10dx", "client1_input_icd10px"}; + + var client = new AmazonGlueClient(accessKeyID, secretKey, RegionEndpoint.USEast1); + + crawlerNames.ToList().ForEach(crawlerName => crawlerName.RunCrawler(client).Dump($"{crawlerName}")); +} + +// Define other methods and classes here diff --git a/HackWeek AWS/HackWeek AWS Glue Upload Files to S3.linq b/HackWeek AWS/HackWeek AWS Glue Upload Files to S3.linq new file mode 100644 index 0000000..1da5339 --- /dev/null +++ b/HackWeek AWS/HackWeek AWS Glue Upload Files to S3.linq @@ -0,0 +1,87 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var sourcePath = @"S:\Development\Cube Killers\Deidentified DI Import Files\Wake - Deidentified"; + var files = Directory.GetFiles(sourcePath, "wfu*.*"); + var uploads = files.Select(f => + { + var s3Name = Regex.Replace(Path.GetFileNameWithoutExtension(f).Replace("_", "/"), @"^(.*)/[\d]{8}$", "${1}"); + var subdir = string.Join("/", s3Name.Split('/').TakeAllButLast()); + var keyName = s3Name.Split('/').Last(); + return new + { + fullName = f, + fileName = Path.GetFileNameWithoutExtension(f), + s3Name, + subdir, + keyName + }; + }); + + uploads.Dump("Uploads"); + var accessKeyID = Util.GetPassword("aws.sdt-tlamb.accessid"); + var secretKey = Util.GetPassword("aws.sdt-tlamb.secretid"); + var bucketName = "sdt-glue-hackweek"; + + var client = new AmazonS3Client(accessKeyID, secretKey, RegionEndpoint.USEast1); + var oldFiles = bucketName.AWSListBucket(client).S3Objects.Where(f => f.Key.StartsWith("wfu/")).ToList(); + oldFiles.ForEach(f => client.DeleteObject(bucketName, f.Key)); + bucketName.AWSListBucket(client).S3Objects.Dump("Before"); + uploads.ToList().ForEach(u => u.fullName.AWSUploadAsync(client, bucketName, u.keyName, u.s3Name)); + bucketName.AWSListBucket(client).S3Objects.Dump("After"); +} + +// Define other methods and classes here diff --git a/Heatmap Facility Deaths.linq b/Heatmap Facility Deaths.linq new file mode 100644 index 0000000..309b04d --- /dev/null +++ b/Heatmap Facility Deaths.linq @@ -0,0 +1,58 @@ + + + ce6f5caf-a955-42be-a634-5eb79966aca4 + true + D0017-SQL-01.sdt.local + jazz tst Aurora 20160126.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + + +var dataRun = from i in ((from fpes in FactPatientEncounterSummaries +where fpes.DischargeDateTime > fpes.AdmitDateTime +&& fpes.DateofDeath >= fpes.AdmitDateTime +&& fpes.DateofDeath >= fpes.DischargeDateTime.AddDays(-30) && fpes.DateofDeath <= fpes.DischargeDateTime.AddDays(30) +&& fpes.AdmitDateTime >= new DateTime(2015,1,1) +select new { fpes.FiscalYearID, fpes.EntityID, fpes.FacilityID, fpes.AttendPhysicianID, fpes.PrimaryPhysicianID, fpes.MSDRGCaseTypeFamilyID +, fpes.AdmitDateTime, fpes.DischargeDateTime, fpes.DateofDeath, fpes.PatientID, fpes.LengthOfStay }) +.Take(10000)) +group i by new { i.FiscalYearID, i.EntityID, i.FacilityID +, i.AttendPhysicianID +, i.PrimaryPhysicianID +, AdmitDateTimeYr = i.AdmitDateTime.Year +, AdmitDateTimeMo = i.AdmitDateTime.Month +, CaseTypeFamilyID= i.MSDRGCaseTypeFamilyID +, DischargeDateTimeYr = i.DischargeDateTime.Year +, DischargeDateTimeMo = i.DischargeDateTime.Month +, DateofDeathYr = i.DateofDeath.Year +, DateofDeathMo = i.DateofDeath.Month +} into g +select new { g.Key.FiscalYearID, g.Key.EntityID, g.Key.FacilityID +, g.Key.AttendPhysicianID +, g.Key.PrimaryPhysicianID +, g.Key.AdmitDateTimeYr +, g.Key.AdmitDateTimeMo +, g.Key.CaseTypeFamilyID +, g.Key.DischargeDateTimeYr +, g.Key.DischargeDateTimeMo +, g.Key.DateofDeathYr +, g.Key.DateofDeathMo +, MinDeath = (int)g.Min(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, MaxDeath = (int)g.Max(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, AvgDeath = (int)g.Average(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, DeceasedPatients = g.Count() +, AvgLOS = (int)g.Average(rl => rl.LengthOfStay) } +; + +(from data in dataRun +join de in Clientdss_DimEntities on data.EntityID equals de.EntityID +group data by new { data.EntityID, de.Name } into g +orderby g.Key.EntityID +select new { g.Key.EntityID, g.Key.Name, DeceasedPatients = g.Sum(rl => rl.DeceasedPatients) }).Dump(); + diff --git a/Heatmap Raw Data.linq b/Heatmap Raw Data.linq new file mode 100644 index 0000000..c104536 --- /dev/null +++ b/Heatmap Raw Data.linq @@ -0,0 +1,111 @@ + + + ce6f5caf-a955-42be-a634-5eb79966aca4 + true + D0017-SQL-01.sdt.local + jazz tst Aurora 20160126.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + + +var dataRun = from i in ( + (from fpes in FactPatientEncounterSummaries + where fpes.DischargeDateTime > fpes.AdmitDateTime + && fpes.DateofDeath >= fpes.AdmitDateTime + && fpes.DateofDeath >= fpes.DischargeDateTime.AddDays(-30) && fpes.DateofDeath <= fpes.DischargeDateTime.AddDays(30) + && fpes.AdmitDateTime >= new DateTime(2015,1,1) + select new { fpes.FiscalYearID, fpes.EntityID, fpes.FacilityID, fpes.AttendPhysicianID, fpes.PrimaryPhysicianID, fpes.MSDRGCaseTypeFamilyID + , fpes.AdmitDateTime, fpes.DischargeDateTime, fpes.DateofDeath, fpes.PatientID, fpes.LengthOfStay }) + .Take(10000) +) +group i by new { i.FiscalYearID, i.EntityID, i.FacilityID +, i.AttendPhysicianID +, i.PrimaryPhysicianID +, AdmitDateTimeYr = i.AdmitDateTime.Year +, AdmitDateTimeMo = i.AdmitDateTime.Month +, CaseTypeFamilyID= i.MSDRGCaseTypeFamilyID +, DischargeDateTimeYr = i.DischargeDateTime.Year +, DischargeDateTimeMo = i.DischargeDateTime.Month +, DateofDeathYr = i.DateofDeath.Year +, DateofDeathMo = i.DateofDeath.Month +} into g +join de in Clientdss_DimEntities on g.Key.EntityID equals de.EntityID +join df in DimFacilities on g.Key.FacilityID equals df.FacilityID +join dpAttend in DimPhysicians on g.Key.AttendPhysicianID equals dpAttend.PhysicianID +join dpPrimary in DimPhysicians on g.Key.PrimaryPhysicianID equals dpPrimary.PhysicianID +join ctf in CaseTypeFamilies on g.Key.CaseTypeFamilyID equals ctf.CaseTypeFamilyID +orderby g.Key.FiscalYearID, g.Key.EntityID, g.Key.FacilityID +select new { g.Key.FiscalYearID +//, g.Key.EntityID +, Entity = de.Name +//, g.Key.FacilityID +, Facility = df.Name +//, g.Key.AttendPhysicianID +, Attenring = dpAttend.Physician +//, g.Key.PrimaryPhysicianID +, Primary = dpPrimary.Physician +, CaseTypeFamily = ctf.Name +, g.Key.AdmitDateTimeYr +, g.Key.AdmitDateTimeMo +, g.Key.CaseTypeFamilyID +, g.Key.DischargeDateTimeYr +, g.Key.DischargeDateTimeMo +, g.Key.DateofDeathYr +, g.Key.DateofDeathMo +, MinDeath = (int)g.Min(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, MaxDeath = (int)g.Max(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, AvgDeath = (int)g.Average(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, DeceasedPatients = g.Count() +, AvgLOS = (int)g.Average(rl => rl.LengthOfStay) } +; + +dataRun.Dump(); +/* +(from i in (from data in dataRun group data by new { data.AttendPhysicianID } into g select g.First()) +join dp in DimPhysicians on i.AttendPhysicianID equals dp.PhysicianID +orderby i.AttendPhysicianID +select new { i.AttendPhysicianID, Attending = dp.Physician }).Dump(); + +(from i in (from data in dataRun group data by new { data.PrimaryPhysicianID } into g select g.First()) +join dp in DimPhysicians on i.PrimaryPhysicianID equals dp.PhysicianID +orderby i.PrimaryPhysicianID +select new { i.PrimaryPhysicianID, Primary = dp.Physician }).Dump(); + +(from i in (from data in dataRun group data by new { data.CaseTypeFamilyID } into g select g.First()) +join ctf in CaseTypeFamilies on i.CaseTypeFamilyID equals ctf.CaseTypeFamilyID +orderby i.CaseTypeFamilyID +select new { i.CaseTypeFamilyID, CaseTypeFamily = ctf.Name }).Dump(); + +var result = +from data in dataRun +join de in Clientdss_DimEntities on data.EntityID equals de.EntityID +join df in DimFacilities on data.FacilityID equals df.FacilityID +join dpAttend in DimPhysicians on data.AttendPhysicianID equals dpAttend.PhysicianID +join dpPrimary in DimPhysicians on data.PrimaryPhysicianID equals dpPrimary.PhysicianID +join ctf in CaseTypeFamilies on data.CaseTypeFamilyID equals ctf.CaseTypeFamilyID +orderby data.FiscalYearID, data.EntityID, data.FacilityID, data.AdmitDateTimeYr, data.AdmitDateTimeMo, data.CaseTypeFamilyID +select new { data.FiscalYearID, data.EntityID +, Entity = de.Name +, data.FacilityID +, Facility = df.Name +, data.AttendPhysicianID +, Attending = dpAttend.Physician +, data.PrimaryPhysicianID +, Primary = dpPrimary.Physician +, AdmitDate = $"{data.AdmitDateTimeYr:0000}/{data.AdmitDateTimeMo:00}" +, data.CaseTypeFamilyID +, CaseTypeFamily = ctf.Name +, DischargeDate = $"{data.DischargeDateTimeYr:0000}/{data.DischargeDateTimeMo:00}" +, DateOfDeath = $"{data.DateofDeathYr:0000}/{data.DateofDeathMo:00}" +, data.MinDeath +, data.MaxDeath +, data.AvgDeath +, data.DeceasedPatients +, data.AvgLOS}; +*/ diff --git a/Heatmp Data Linq2Sql.linq b/Heatmp Data Linq2Sql.linq new file mode 100644 index 0000000..3ab0dab --- /dev/null +++ b/Heatmp Data Linq2Sql.linq @@ -0,0 +1,105 @@ + + + ce6f5caf-a955-42be-a634-5eb79966aca4 + true + D0017-SQL-01.sdt.local + jazz tst Aurora 20160126.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + + +var dataRun = from i in ((from fpes in FactPatientEncounterSummaries +where fpes.DischargeDateTime > fpes.AdmitDateTime +&& fpes.DateofDeath >= fpes.AdmitDateTime +&& fpes.DateofDeath >= fpes.DischargeDateTime.AddDays(-30) && fpes.DateofDeath <= fpes.DischargeDateTime.AddDays(30) +&& fpes.AdmitDateTime >= new DateTime(2015,1,1) +select new { fpes.FiscalYearID, fpes.EntityID, fpes.FacilityID, fpes.AttendPhysicianID, fpes.PrimaryPhysicianID, fpes.MSDRGCaseTypeFamilyID +, fpes.AdmitDateTime, fpes.DischargeDateTime, fpes.DateofDeath, fpes.PatientID, fpes.LengthOfStay }) +.Take(10000)) +group i by new { i.FiscalYearID, i.EntityID, i.FacilityID +, i.AttendPhysicianID +, i.PrimaryPhysicianID +, AdmitDateTimeYr = i.AdmitDateTime.Year +, AdmitDateTimeMo = i.AdmitDateTime.Month +, CaseTypeFamilyID= i.MSDRGCaseTypeFamilyID +, DischargeDateTimeYr = i.DischargeDateTime.Year +, DischargeDateTimeMo = i.DischargeDateTime.Month +, DateofDeathYr = i.DateofDeath.Year +, DateofDeathMo = i.DateofDeath.Month +} into g +select new { g.Key.FiscalYearID, g.Key.EntityID, g.Key.FacilityID +, g.Key.AttendPhysicianID +, g.Key.PrimaryPhysicianID +, g.Key.AdmitDateTimeYr +, g.Key.AdmitDateTimeMo +, g.Key.CaseTypeFamilyID +, g.Key.DischargeDateTimeYr +, g.Key.DischargeDateTimeMo +, g.Key.DateofDeathYr +, g.Key.DateofDeathMo +, MinDeath = (int)g.Min(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, MaxDeath = (int)g.Max(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, AvgDeath = (int)g.Average(rl => Math.Abs((rl.DateofDeath - rl.DischargeDateTime).TotalDays)) +, DeceasedPatients = g.Count() +, AvgLOS = (int)g.Average(rl => rl.LengthOfStay) } +; + +(from i in (from data in dataRun group data by new { data.EntityID } into g select g.First()) +join de in Clientdss_DimEntities on i.EntityID equals de.EntityID +orderby i.EntityID +select new { i.EntityID, Entity = de.Name }).Dump(); + +(from i in (from data in dataRun group data by new { data.FacilityID } into g select g.First()) +join df in DimFacilities on i.FacilityID equals df.FacilityID +orderby i.FacilityID +select new { i.FacilityID, Facility = df.Name }).Dump(); + +(from i in (from data in dataRun group data by new { data.AttendPhysicianID } into g select g.First()) +join dp in DimPhysicians on i.AttendPhysicianID equals dp.PhysicianID +orderby i.AttendPhysicianID +select new { i.AttendPhysicianID, Attending = dp.Physician }).Dump(); + +(from i in (from data in dataRun group data by new { data.PrimaryPhysicianID } into g select g.First()) +join dp in DimPhysicians on i.PrimaryPhysicianID equals dp.PhysicianID +orderby i.PrimaryPhysicianID +select new { i.PrimaryPhysicianID, Primary = dp.Physician }).Dump(); + +(from i in (from data in dataRun group data by new { data.CaseTypeFamilyID } into g select g.First()) +join ctf in CaseTypeFamilies on i.CaseTypeFamilyID equals ctf.CaseTypeFamilyID +orderby i.CaseTypeFamilyID +select new { i.CaseTypeFamilyID, CaseTypeFamily = ctf.Name }).Dump(); + +var result = +from data in dataRun +join de in Clientdss_DimEntities on data.EntityID equals de.EntityID +join df in DimFacilities on data.FacilityID equals df.FacilityID +join dpAttend in DimPhysicians on data.AttendPhysicianID equals dpAttend.PhysicianID +join dpPrimary in DimPhysicians on data.PrimaryPhysicianID equals dpPrimary.PhysicianID +join ctf in CaseTypeFamilies on data.CaseTypeFamilyID equals ctf.CaseTypeFamilyID +orderby data.FiscalYearID, data.EntityID, data.FacilityID, data.AdmitDateTimeYr, data.AdmitDateTimeMo, data.CaseTypeFamilyID +select new { data.FiscalYearID, data.EntityID +, Entity = de.Name +, data.FacilityID +, Facility = df.Name +, data.AttendPhysicianID +, Attending = dpAttend.Physician +, data.PrimaryPhysicianID +, Primary = dpPrimary.Physician +, AdmitDate = $"{data.AdmitDateTimeYr:0000}/{data.AdmitDateTimeMo:00}" +, data.CaseTypeFamilyID +, CaseTypeFamily = ctf.Name +, DischargeDate = $"{data.DischargeDateTimeYr:0000}/{data.DischargeDateTimeMo:00}" +, DateOfDeath = $"{data.DateofDeathYr:0000}/{data.DateofDeathMo:00}" +, data.MinDeath +, data.MaxDeath +, data.AvgDeath +, data.DeceasedPatients +, data.AvgLOS}; + +result.Dump(); \ No newline at end of file diff --git a/Information Schema.linq b/Information Schema.linq new file mode 100644 index 0000000..6fc885c --- /dev/null +++ b/Information Schema.linq @@ -0,0 +1,140 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.Runtime.Remoting.Contexts + + +void Main() +{ + GetColumns(); +} + +public void GetSchema() +{ + var schemata = ExecuteQuery("select * from Information_Schema.SCHEMATA") + .GroupBy(g => g.CATALOG_NAME, (Key, Data) => new { Key, Data = Data.OrderBy(d => d.SCHEMA_OWNER).ThenBy(d => d.SCHEMA_NAME).ToList() }) + .OrderBy(grp => grp.Key) + .ToList(); + schemata.Dump(); +} + +public void GetTables(string schema = null) +{ + var tables = ExecuteQuery
($"select * from Information_Schema.TABLES AS t WHERE t.TABLE_SCHEMA = '{schema}'") + .GroupBy(x => new { x.TABLE_SCHEMA, x.TABLE_TYPE }, + (Key, Tables) => new { Schema = Key.TABLE_SCHEMA, Type = Key.TABLE_TYPE, Tables = Tables.Select(ta => ta.TABLE_NAME).OrderBy(ta => ta).ToList() }); + tables.Dump(); +} + +public void GetColumns(string schema = null) +{ + // var tableDefs = tables.Where(t => t.Schema == schema).SelectMany(t => t.Tables.Select(ta => + // ExecuteQuery($"select * from Information_Schema.COLUMNS AS c WHERE c.TABLE_SCHEMA = '{t.Schema}' AND c.TABLE_NAME = '{ta}'"))); + var tableDefs = ExecuteQuery($"select * from Information_Schema.COLUMNS AS c") + .GroupBy(c => new Table {TABLE_CATALOG= c.TABLE_CATALOG, TABLE_SCHEMA = c.TABLE_SCHEMA, TABLE_TYPE = c.TABLE_NAME }, + (Key, Columns) => new { Key, Columns = Columns.OrderBy(c => c.ORDINAL_POSITION).ToList() }) + .OrderBy(c => c.Key.TABLE_CATALOG) + .ThenBy(c => c.Key.TABLE_SCHEMA) + .ThenBy(c => c.Key.TABLE_NAME); + tableDefs.Dump(); +} + +// Define other methods and classes here +public class Schemata +{ + public string CATALOG_NAME { get; set; } + public string SCHEMA_NAME { get; set; } + public string SCHEMA_OWNER { get; set; } +} + +public class Table +{ + public string TABLE_CATALOG { get; set; } + public string TABLE_SCHEMA { get; set; } + public string TABLE_NAME { get; set; } + public string TABLE_TYPE { get; set; } +} + +public class TableColumn +{ + public string TABLE_CATALOG { get; set; } + public string TABLE_SCHEMA { get; set; } + public string TABLE_NAME { get; set; } + public string COLUMN_NAME { get; set; } + public int? ORDINAL_POSITION { get; set; } + public string COLUMN_DEFAULT { get; set; } + public string IS_NULLABLE { get; set; } + public string DATA_TYPE { get; set; } + public int? CHARACTER_MAXIMUM_LENGTH { get; set; } + public int? CHARACTER_OCTET_LENGTH { get; set; } + public byte? NUMERIC_PRECISION { get; set; } + public short? NUMERIC_PRECISION_RADIX { get; set; } + public int? NUMERIC_SCALE { get; set; } + public short? DATETIME_PRECISION { get; set; } + public string CHARACTER_SET_CATALOG { get; set; } + public string CHARACTER_SET_SCHEMA { get; set; } + public string CHARACTER_SET_NAME { get; set; } + public string COLLATION_CATALOG { get; set; } + public string COLLATION_SCHEMA { get; set; } + public string COLLATION_NAME { get; set; } + public string DOMAIN_CATALOG { get; set; } + public string DOMAIN_SCHEMA { get; set; } + public string DOMAIN_NAME { get; set; } +} + diff --git a/JAZZ-10828 CTF Definitions/Convert CSV file to CTF definitions.linq b/JAZZ-10828 CTF Definitions/Convert CSV file to CTF definitions.linq new file mode 100644 index 0000000..d0f36f9 --- /dev/null +++ b/JAZZ-10828 CTF Definitions/Convert CSV file to CTF definitions.linq @@ -0,0 +1,111 @@ + + + 580b3b8d-cc02-4a68-8fbd-d1ec374a25f2 + true + D0001-sql-11.sdt.local + jazz dev master Prod + true + + LinqToCsv + LINQtoCSV + + +void Main() +{ + var path = @"D:\Users\tlamb\Downloads"; + var fileName = @"FY2020 New Codes_04242020_Final.csv"; + + var filePath = Path.Combine(path, fileName); + if (!File.Exists(filePath)) return; + + //var data = File.ReadAllLines(filePath); + //data.Dump(); + + var inputFileDescription = new CsvFileDescription + { + SeparatorChar = ',', + FirstLineHasColumnNames = true + }; + + var ctfVersion = CaseTypeFamilyVersions.Any(x => x.Name.Equals("2019 Standard Mapping")) + ? (from x in CaseTypeFamilyVersions + where x.Name.Equals("2019 Standard Mappings") + select x.CaseTypeFamilyVersionID).FirstOrDefault() + : 2; + //ctfVersion.Dump(); + + var cc = new CsvContext(); + var dat = from x in cc.Read(filePath, inputFileDescription) + select new + { + ctfVersion, + x.Column1, + x.MS_DRG_Code, + x.MDC, + x.ICD10Code, + x.ICD10_Code_Description, + x.Code_Type_1DX_3PX, + Exclusion_Type = (x.Exclusion_Type == "N"), + x.DRGs_to_CTFs, + ICD_Needs_Review = (x.ICD_Needs_Review != "#N/A"), + x.CTF_Type, + Same_Type = (x.Same_Type == "Yes"), + CTF_To_Assign_Existing = (x.CTF_To_Assign_Existing ?? "").Replace("&", "And"), + New_CTF = ((x.New_CTF ?? "No") == "Yes") + }; + //dat.Dump(); + + var xCTF_To_Assign = dat.Select(d => d.CTF_To_Assign_Existing).Distinct(); + var ctf = CaseTypeFamilies + .Where(c => xCTF_To_Assign.Contains(c.Name)) + .GroupBy(c => c.Name, (g, d) => new { name = g, ids = d.Select(x => x.CaseTypeFamilyID).ToList() }) + .ToDictionary(c => c.name, c => c.ids); + //ctf.Aggregate("", (x, y) => $"{x}\r\nUNION\r\nSelect Name, Case Name when '{y.Key}' THEN 1 ELSE 0 END isMatch from dss.CaseTypeFamily where CaseTypeFamilyID = {y.Value.First()}").Substring(9) .Dump(); + + var msDrg = dat + .Where(d => !string.IsNullOrEmpty(d.ICD10Code)) + .ToList() + .ConvertAll(d => + { + var caseTypeFamilyID = ctf.TryGetValue(d.CTF_To_Assign_Existing, out var value) + ? value.FirstOrDefault() + : 0; + return new + { + CaseTypeFamilyID = caseTypeFamilyID, + CTFExisting = d.CTF_To_Assign_Existing, + SkipICD = false, + ICD10Code = d.ICD10Code.Replace(".",""), + MSDRGCode = d.MS_DRG_Code, + CaseTypeFamilyVersionID = d.ctfVersion + }; + }) + //.Where(d => d.ICD10Code.Contains(".")) + .Aggregate("", (x, y) => $@"{x} + +INSERT INTO dss.CaseTypeFamilyMappingICD10 +( CaseTypeFamilyID, SkipICD, ICD10Code, MSDRGCode, CaseTypeFamilyVersionID ) +SELECT ctf.CaseTypeFamilyID,{(y.SkipICD ? 1 : 0)},'{y.ICD10Code}','{y.MSDRGCode}',{y.CaseTypeFamilyVersionID} +FROM dss.CaseTypeFamily ctf +WHERE ctf.Name = '{y.CTFExisting}'") + .Substring(4); + msDrg.Dump(); +} + +// Define other methods and classes here +public class CTFDefinitions +{ + public string Column1 { get; set; } + public string MS_DRG_Code { get; set; } + public string MDC { get; set; } + public string ICD10Code { get; set; } + public string ICD10_Code_Description { get; set; } + public string Code_Type_1DX_3PX { get; set; } + public string Exclusion_Type { get; set; } + public string DRGs_to_CTFs { get; set; } + public string ICD_Needs_Review { get; set; } + public string CTF_Type { get; set; } + public string Same_Type { get; set; } + public string CTF_To_Assign_Existing { get; set; } + public string New_CTF { get; set; } +} diff --git a/JAZZ-14426 Create SQL.linq b/JAZZ-14426 Create SQL.linq new file mode 100644 index 0000000..6ddccbf --- /dev/null +++ b/JAZZ-14426 Create SQL.linq @@ -0,0 +1,79 @@ + + + bd4e97c5-84e7-4c61-80ca-8d53d7876af2 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + System.Globalization + + +void Main() +{ + var ti = CultureInfo.CurrentCulture.TextInfo; + var _2020MSDRGs = (from x in DimMSDRGs where x.DRGSchema == "2020MSDRG" select x.MSDRGCode).Distinct(); + var _caseTypeFamilyMappingICD10 = (from x in CaseTypeFamilyMappingICD10s select x.MSDRGCode).Distinct(); + var _ctfGlobalID = (from x in CaseTypeFamilies where x.CaseTypeFamilyGlobalID.StartsWith("M-") select x.CaseTypeFamilyGlobalID) + .ToList() + .Where(x => Regex.IsMatch(x, @"M-\d+")) + .Select(x => int.Parse(Regex.Replace(x, @"M-(\d+)", "$1"))) + .OrderByDescending(x => x) + //.Select(x => $"M-{x}") + .First(); + //_ctfGlobalID.Dump(); + var part1 = (from msdrg in DimMSDRGs + where msdrg.DRGSchema == "2021MSDRG" + && !_2020MSDRGs.Contains(msdrg.MSDRGCode) + select new + { + msdrg.MSDRGCode, + CaseTypeFamilyName = ti.ToTitleCase(msdrg.Description.ToLower()) + }) + .ToList(); + var part2 = (from msdrg in DimMSDRGs + where msdrg.DRGSchema == "2021MSDRG" + && !_caseTypeFamilyMappingICD10.Contains(msdrg.MSDRGCode) + select new + { + msdrg.MSDRGCode, + CaseTypeFamilyName = ti.ToTitleCase(msdrg.Description.ToLower()) + }) + .ToList(); + var results = part1.Union(part2).ToList() + .ConvertAll(x => + { + _ctfGlobalID++; + return new + { + CaseTypeFamilyGlobalID = $"M-{_ctfGlobalID}", + x.MSDRGCode, + x.CaseTypeFamilyName + }; + }); + //results.Dump("results"); + var deleteCaseTypeFamily = results + .Aggregate("", (x, y) => $"{x}\r\nDELETE FROM dss.CaseTypeFamily WHERE Name = '{y.CaseTypeFamilyName}' AND CaseTypeFamilyGlobalID = '{y.CaseTypeFamilyGlobalID}'"); + var insertCaseTypeFamily = results + .Aggregate($"INSERT INTO dss.CaseTypeFamily ( CaseTypeFamilyGUID, Name, CaseTypeFamilyGlobalID )\r\nVALUES", + (x, y) => $"{x}\r\n('{Guid.NewGuid()}', '{y.CaseTypeFamilyName}', '{y.CaseTypeFamilyGlobalID}'),").TrimEnd(",".ToCharArray()); + var deleteICD10 = results + .Aggregate("", (x, y) => $@"{x} +DELETE FROM dss.CaseTypeFamilyMappingICD10 +WHERE EXISTS(SELECT 1 FROM dss.CaseTypeFamily ctf + WHERE ctf.CaseTypeFamilyGlobalID = '{y.CaseTypeFamilyGlobalID}' AND SkipICD = 1 AND ctf.CaseTypeFamilyID = CaseTypeFamilyMappingICD10.CaseTypeFamilyID) +AND CaseTypeFamilyMappingICD10.MSDRGCode = '{y.MSDRGCode}' AND CaseTypeFamilyVersionID = 2"); + var insertICD10 = results + .Aggregate($"INSERT INTO dss.CaseTypeFamilyMappingICD10 ( CaseTypeFamilyID, SkipICD, ICD10Code, MSDRGCode, CaseTypeFamilyVersionID )\r\nVALUES", + (x, y) => $"{x}\r\n((SELECT ctf.CaseTypeFamilyID from dss.CaseTypeFamily ctf where ctf.CaseTypeFamilyGlobalID = '{y.CaseTypeFamilyGlobalID}'), 1, '0', '{y.MSDRGCode}', 2),").TrimEnd(new[] { ',' }); + + var migration = + deleteCaseTypeFamily + "\r\nGO\r\n" + + insertCaseTypeFamily + "\r\nGO\r\n" + + deleteICD10 + "\r\nGO\r\n" + + insertICD10 + "\r\nGO\r\n"; + + migration.Dump(); +} + +// Define other methods and classes here \ No newline at end of file diff --git a/Kevin Sql Parsing.linq b/Kevin Sql Parsing.linq new file mode 100644 index 0000000..dba2138 --- /dev/null +++ b/Kevin Sql Parsing.linq @@ -0,0 +1,84 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var filePath = @"D:\Git\2020-01-15-13-20 B-24820 UV Case Type Setup CPT Codes.sql"; +var regex = new Regex(@"[\r\n\s]+"); +var regex2 = new Regex(@"^[^']+'(C?[\d]+).+O-([\d]{4}).+$"); +var info = File.ReadAllText(filePath) + .Split(';') + .Select(x => x.TrimStart(new[] { '\r', '\n' })) + .Where(x => x.StartsWith("INSERT INTO [dss].[CaseTypeFamilyMappingCPT]")).ToList() + .ConvertAll(x => + { + x = regex.Replace(x, " "); + var CPTCode = regex2.Replace(x, "$1"); + var GlobalId = regex2.Replace(x, "O-$2"); + return new { GlobalId, CPTCode }; + }) + .GroupBy(x => x.GlobalId, (g, d) => new + { + GlobalId = g, + CPTCodes = d.Select(c => c.CPTCode) + }) + .OrderBy(x => x.GlobalId); +//info.Dump(); +info +.Aggregate(@"DECLARE @CaseTypeFamilyID INT +", (a, b) => $@"{a}SELECT @CaseTypeFamilyID = [CaseTypeFamilyID] FROM [dss].[CaseTypeFamily] WHERE [CaseTypeFamilyGlobalID] = '{b.GlobalId}'; +INSERT INTO [dss].[CaseTypeFamilyMappingCPT] ([CaseTypeFamilyID], [CPTCode], [CaseTypeFamilyVersionID]) +VALUES{b.CPTCodes.Aggregate("", (c, d) => $@"{c} + (@CaseTypeFamilyID, '{d}', 1),").TrimEnd(',')}; + +") +.Dump(); \ No newline at end of file diff --git a/Kevin's Python queries reversed engineered.linq b/Kevin's Python queries reversed engineered.linq new file mode 100644 index 0000000..53b6369 --- /dev/null +++ b/Kevin's Python queries reversed engineered.linq @@ -0,0 +1,105 @@ + + + 40766b24-ff74-431b-b387-6c221ede77cf + true + p3121-sql-02.sdt.local + jazz prd UNC 20180206.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var timeClasses = new[] { 1, 4 }; +var departments = new[] { 115355, 115372, 115373, 45950, 45953, 45955, 45959, 45960, 45967, 45968, 45973, 45974, 45975, 45976, 45977, 45979, 45980, 45982, 45985, 45998, 46030, 59278, 74820 }; +var payperiods = new[] { 3136, 3135, 3134, 3133, 3132, 3131 }; +var hours = from fact in FactPayrollSampledPayPeriods + join payperiod in DimPayPeriods on fact.PayPeriodID equals payperiod.PayPeriodID + join paycode in DimPayCodeGroups on fact.PayCodeGroupID equals paycode.PayCodeGroupID + join prodclass in DimProductiveClasses on paycode.ProductiveClassID equals prodclass.ProductiveClassID + join department in DimDepartments on fact.DepartmentID equals department.DepartmentID + where prodclass.Name == "Productive" + && timeClasses.Contains(fact.TimeClassID) + && departments.Contains(fact.DepartmentID) + && payperiods.Contains(fact.PayPeriodID) + group new { fact, department, payperiod } by new { department.DepartmentID, payperiod.PayPeriodID, fact.TimeClassID } into g + select new { g.Key.DepartmentID, g.Key.PayPeriodID, g.Key.TimeClassID, Units = g.Sum(f => f.fact.Hours), UnitType = "hours" }; + +var dollars = from fact in FactPayrollSampledPayPeriods + join payperiod in DimPayPeriods on fact.PayPeriodID equals payperiod.PayPeriodID + join paycode in DimPayCodeGroups on fact.PayCodeGroupID equals paycode.PayCodeGroupID + join department in DimDepartments on fact.DepartmentID equals department.DepartmentID + where timeClasses.Contains(fact.TimeClassID) + && departments.Contains(fact.DepartmentID) + && payperiods.Contains(fact.PayPeriodID) + group new { fact, department, payperiod } by new { department.DepartmentID, payperiod.PayPeriodID, fact.TimeClassID } into g + select new { g.Key.DepartmentID, g.Key.PayPeriodID, g.Key.TimeClassID, Units = g.Sum(f => f.fact.Dollars), UnitType = "dollars" }; + +var uos = from fact in ViewPrimaryStatisticsStaffingByPayPeriod + join payperiod in DimPayPeriods on fact.PayPeriodID equals payperiod.PayPeriodID + join department in DimDepartments on fact.DepartmentID equals department.DepartmentID + where timeClasses.Contains(fact.TimeClassID) + && departments.Contains(fact.DepartmentID) + && payperiods.Contains(fact.PayPeriodID) + group new { fact, department, payperiod } by new { department.DepartmentID, payperiod.PayPeriodID, fact.TimeClassID } into g + select new { g.Key.DepartmentID, g.Key.PayPeriodID, g.Key.TimeClassID, Units = g.Sum(f => f.fact.Units) ?? 0.0m, UnitType = "uos" }; + +hours.Concat(dollars).Concat(uos) +//.Where(x => departments.Contains(x.DepartmentID) && payperiods.Contains(x.PayPeriodID)) +.Join(DimDepartments, m => m.DepartmentID, d => d.DepartmentID, (m, d) => new { m.DepartmentID, m.PayPeriodID, m.TimeClassID, m.Units, m.UnitType, Department = d.Name }) +.Join(DimPayPeriods, m => m.PayPeriodID, p => p.PayPeriodID, (m, p) => new { m.DepartmentID, m.PayPeriodID, m.TimeClassID, m.Units, m.UnitType, m.Department, p.PeriodStartCalendarDate, p.PeriodEndCalendarDate }) +.Join(DimTimeClasses, m => m.TimeClassID, t => t.TimeClassID, (m, t) => new { m.DepartmentID, m.PayPeriodID, m.TimeClassID, m.Units, m.UnitType, m.Department, m.PeriodStartCalendarDate, m.PeriodEndCalendarDate, t.TimeClassCode, TimeClass = t.Name, t.SortOrder }) +.OrderBy(x => x.DepartmentID) +.ThenBy(x => x.PayPeriodID) +.ThenBy(x => x.UnitType) +.ThenBy(x => x.SortOrder) +.Dump(); \ No newline at end of file diff --git a/Localization DateTime Helpers.linq b/Localization DateTime Helpers.linq new file mode 100644 index 0000000..d9fbcf5 --- /dev/null +++ b/Localization DateTime Helpers.linq @@ -0,0 +1,76 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.Globalization + + +void Main() +{ + var culture = new CultureInfo("en-US"); + var databaseTime = new DateTime(1900,9,9,13,9,09, DateTimeKind.Utc); + GetUTCLocalDateTime(databaseTime).ToString(culture.DateTimeFormat.ShortDatePattern).Dump(); +} + +// Define other methods and classes here +/// +/// convert UTC time from the database to the machine's time +/// +/// +/// +internal DateTime GetUTCLocalDateTime(DateTime dateTime) +{ + var localTime = dateTime.ToLocalTime(); + + // convert local time to UTC for database save + var utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(localTime); + return localTime.ToUniversalTime().Subtract(utcOffset); +} diff --git a/MailGun Test with Template Data.linq b/MailGun Test with Template Data.linq new file mode 100644 index 0000000..495d4ad --- /dev/null +++ b/MailGun Test with Template Data.linq @@ -0,0 +1,175 @@ + + + 40766b24-ff74-431b-b387-6c221ede77cf + true + p3121-sql-02.sdt.local + jazz prd UNC 20180206.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + RestSharp.Authenticators + + +private static string baseurl = "https://dev.sdt.local/StrataJazz201931"; +private static Random _rnd; + +void Main() +{ + var now = DateTime.Today.AddDays(-1 * (7 + ((DateTime.Today.DayOfWeek - DayOfWeek.Monday)) % 7)); + var staffing = new Staffing + { + pr = new PayPeriod + { + StartDate = now.AddDays(-14), + EndDate = now.AddDays(-7) + }, + Departments = Enumerable.Range(0, 26).ToList() + .ConvertAll(e => //new Department { department = + new DeptInfo($"dept_{e}", Random.Next() * 10m, Random.Next() * 10m, Random.Next() * 10m * Random.Next(-1, 1)) + //} + ) + }; + var data = JsonConvert.SerializeObject(staffing); + data.Dump(); + SendMessageByTemplateId(data).Content.Dump(); +} + +internal static Random Random +{ + get => _rnd ?? (_rnd = new Random()); + set => _rnd = value; +} + +// Define other methods and classes here +public class Staffing +{ + public PayPeriod pr { get; set; } + public List overall => new List { Departments.FirstOrDefault() }; + public List departments => new List + { + new DeptInfo( + $"Current Pay Period ({pr.endDate:M/dd})", + Departments.Sum(d => d.latest_total_variance), + Departments.Sum(d => d.latest_pay_variance), + Departments.Sum(d => d.latest_flex_variance) + ) + }; + internal List Departments { get; set; } +} + +public class PayPeriod +{ + internal DateTime StartDate { get; set; } + internal DateTime EndDate { get; set; } + public string startDate => StartDate.ToString("MM/dd"); + public string endDate => EndDate.ToString("MM/dd"); +} + +public class Department +{ + public DeptInfo department { get; set; } +} + +public class DeptInfo +{ + public string hyperlink => baseurl; + public string name { get; set; } + internal decimal latest_total_variance { get; set; } + internal decimal latest_pay_variance { get; set; } + internal decimal latest_flex_variance { get; set; } + public string total_variance => $"{latest_total_variance:C}"; + public string pay_variance => $"{latest_pay_variance:C}"; + public string flex_variance => $"{latest_flex_variance:C}"; + public string six_month_total_chart => "graph_sparkline_6_pay_period_-1281183930.png"; + public string six_month_pay_chart => "graph_sparkline_6_pay_period_1140344931.png"; + public string six_month_flex_chart => "graph_sparkline_6_pay_period_489356044.png"; + public string total_color => latest_total_variance >= 0 ? "positive" : "negative"; + public string pay_color => latest_pay_variance >= 0 ? "positive" : "negative"; + public string flex_color => latest_flex_variance >= 0 ? "positive" : "negative"; + + public DeptInfo(string deptName, decimal total, decimal pay, decimal flex) + { + name = deptName; + latest_total_variance = total; + latest_pay_variance = pay; + latest_flex_variance = flex; + } +} + +public static IRestResponse SendMessageByTemplateId(string jsonStr) +{ + RestClient client = new RestClient(); + client.BaseUrl = new Uri("https://api.mailgun.net/v3/notifications-dev.stratanetwork.com"); + client.Authenticator = + new HttpBasicAuthenticator("api", + "key-12ea6389d906cef290ad8a0557a3a8c4"); + RestRequest request = new RestRequest(); + //request.AddParameter("domain", "notifications.stratanetwork.com", ParameterType.UrlSegment); + //request.Resource = "{domain}/messages"; + request.Resource = "/messages"; + request.AddParameter("from", "Mailgun Sandbox "); + //request.AddParameter("to", "Dhara "); + //request.AddParameter("to", "Nicole "); + request.AddParameter("to", "Thom Lamb "); + //request.AddParameter("to", "Kevin Lamb "); + //request.AddParameter("to", "Shruthi Agni "); + //request.AddParameter("to", "Tucker Debolt "); + request.AddParameter("subject", "Hello Thom Lamb"); + //request.AddParameter("template", "daily_pr_snapshot"); + request.AddParameter("template", "overall_pr_notification"); + request.AddParameter("h:X-Mailgun-Variables", jsonStr); + request.Method = Method.POST; + return client.Execute(request); +} \ No newline at end of file diff --git a/MonthNames.linq b/MonthNames.linq new file mode 100644 index 0000000..09ee294 --- /dev/null +++ b/MonthNames.linq @@ -0,0 +1,68 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + TimeZoneNames + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.Globalization + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + TimeZoneNames + + +Enumerable.Range(1, 12).ToList() + .Select(mm => new { Key = mm, Value = CultureInfo.GetCultureInfo("hi-IN").DateTimeFormat.GetMonthName(mm) }) + .ToDictionary(item => item.Key, item => item.Value) + .Dump(); diff --git a/Move files to new name.linq b/Move files to new name.linq new file mode 100644 index 0000000..a7e31c5 --- /dev/null +++ b/Move files to new name.linq @@ -0,0 +1,95 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var dir = @"D:\Git\stratasphere.web.api.service"; +var files = Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories) + .Select(d => new + { + file = d, + dir = Path.GetDirectoryName(d), + oldFile = Path.GetFileName(d), + ext = Path.GetExtension(d) + }) + //.Where(d => !d.dir.Contains(".git")) + .Select(d => new + { + d.file, + d.dir, + d.oldFile, + d.ext, + newFile = d.oldFile.Contains("StrataSphere") ? d.oldFile.Replace("StrataSphere", "StarterSet") : "" + }) + .Where(d => !d.dir.Contains(".git") && !string.IsNullOrEmpty(d.newFile)) + .Select(d => new + { + d.file, + d.dir, + d.oldFile, + d.ext, + d.newFile, + moveTo = string.IsNullOrEmpty(d.newFile) ? "" : Path.Combine(d.dir, d.newFile) + }); +files.Dump(); +files.ToList() +.ForEach(f => +{ + var moveTo = Path.Combine(f.dir, f.newFile); + try + { + $"Directory.Move({f.file}, {moveTo});".Dump(); + Directory.Move(f.file, moveTo); + } + catch (Exception ex) + { } +}); \ No newline at end of file diff --git a/New StarterSet Cube Parameters.linq b/New StarterSet Cube Parameters.linq new file mode 100644 index 0000000..6b4b8d3 --- /dev/null +++ b/New StarterSet Cube Parameters.linq @@ -0,0 +1,79 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + jazz tst StrataSphere 20191104.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var insert = (from rcrp in REDSCubeReportParameters +join sd in ScoreDimensions on rcrp.Name equals sd.FriendlyName +join sh in ScoreHierarchies on sd.DefaultHierarchyGUID equals sh.HierarchyGUID +select new {rcrp.Name, rcrp.DimensionID, rcrp.AttributeID, sd.DimensionGUID, HierarchyGUID = sd.DefaultHierarchyGUID, AttributeGUID = sd.DefaultLookupKeyGUID, sh.HierarchyID}) +.Distinct() +.ToList() +.Aggregate(@"INSERT INTO stratasphere.Definition +( Id, Name, Description, DateCreated, DateLastModified, AttributeGuid, DimensionGuid, AttributeId, DimensionId, HierarchyGuid, HierarchyId ) +SELECT Id, Name, Description, DateCreated, DateLastModified, AttributeGUID, DimensionGuid, AttributeID, DimensionId, HierarchyGuid, HierarchyId +FROM ( +VALUES +", (x, y) => $@"{x}(NEWID(),'{y.Name}','{y.Name}',SYSDATETIME(),SYSDATETIME(),'{y.AttributeGUID}','{y.DimensionGUID}','{y.AttributeID}','{y.DimensionID}','{y.HierarchyGUID}','{y.HierarchyID}'), +"); +insert += @") AS x (Id, Name, Description, DateCreated, DateLastModified, AttributeGUID, DimensionGuid, AttributeID, DimensionId, HierarchyGuid, HierarchyId) +WHERE NOT EXISTS (SELECT 1 FROM stratasphere.Definition d WHERE d.Name = x.Name +OR (d.DimensionId = x.DimensionId AND d.AttributeId = x.AttributeID) +OR (d.DimensionGUID = x.DimensionGUID AND d.AttributeGUID = x.AttributeGUID))"; +insert.Dump(); \ No newline at end of file diff --git a/Nursing Census Data Analysis.linq b/Nursing Census Data Analysis.linq new file mode 100644 index 0000000..d14973e --- /dev/null +++ b/Nursing Census Data Analysis.linq @@ -0,0 +1,161 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + jazz tst CNE 20191210.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var configurationGuid = Guid.Parse("880C4912-5A58-40B7-ADB1-1F9BD365E6AF"); + (from sd in StaffingToDemandPatientVolumes + where new[] {21398, 21915}.Contains(sd.DepartmentID) + select sd).ToList() + .OrderBy(g => g.DepartmentID) + .ThenBy(g => g.IsBaseline) + .ThenBy(g => g.DayOfWeek) + .ThenBy(g => g.Seasonality) + .ThenBy(g => g.Hour) + + .Dump(nameof(StaffingToDemandPatientVolumes)); + var CensusData = + from obj in Nursings + join f in DimFunctionalAreas on obj.DimDepartment.FunctionalAreaID equals f.FunctionalAreaID + join fj in NursingFlexJobCodeGroups on obj.NursingGUID equals fj.NursingGUID + join j in DimFlexJobCodeGroups on fj.FlexJobCodeGroupID equals j.FlexJobCodeGroupID + where obj.ConfigurationGUID == configurationGuid + select new + { + obj.DepartmentID, + obj.NumOfBeds, + obj.IsComplete, + obj.IsNewborn, + InPatientDays = new FlattenDays("InPatientDays", obj).Values, + ObservationDays = new FlattenDays("ObservationDays", obj).Values, + NewbornInPatientDays = new FlattenDays("NewbornInPatientDays", obj).Values, + NewbornObservationDays = new FlattenDays("NewbornObservationDays", obj).Values, + Seasonality = new FlattenSeasonality("Seasonality", obj).Values, + obj.DimDepartment.Name, + FunctionalAreaName = f.Name, + fj.WHPPDBaseline, + fj.MedianAnnualWageBaseline, + fj.DirectCarePercentageBaseline, + fj.UnproductivePercentBaseline, + fj.WHPPD, + fj.MedianAnnualWage, + fj.DirectCarePercentage, + fj.UnproductivePercent, + fj.PatientCare, + fj.AcutyAdjustment, + fj.RoundingRule, + fj.FlexJobCodeGroupID, + fj.StaffingModelType, + StaffingModelConfig = Newtonsoft.Json.JsonConvert.DeserializeObject(fj.StaffingModelConfig),//.PatientRatios, + JobName = j.Name, + j.Code, + j.SortOrder + }; + CensusData.Where(cd => new [] {"2310 - 11150 - DELIVERY","2110 - 11071 - RIVERVIEW 3"}.Contains(cd.Name) && cd.JobName == "RN").Dump(); +} + +// Define other methods and classes here +public class ModelValue +{ + public IList ModelValues { get; set; } + internal Dictionary> PatientRatios => ModelValues + .GroupBy(mv => mv.DayOfWeek, (dayOfWeek, d) => new + { + dayOfWeek, + HourlyRatios = d.Select(x => new { x.HourOfDay, x.PatientRatio }) + .ToDictionary(key => key.HourOfDay, value => value.PatientRatio) + }).ToDictionary(key => key.dayOfWeek, value => value.HourlyRatios); +} + +public class StaffingModel +{ + public int DayOfWeek { get; set; } + public int HourOfDay { get; set; } + public double PatientRatio { get; set; } +} + +public class FlattenDays +{ + public IEnumerable Values { get; set; } + public FlattenDays(string name, Nursing obj) + { + var regex = new Regex($"Month[\\d]{{2}}{name}", RegexOptions.IgnoreCase); + Type t = typeof(Nursing); + var fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance) + .Where(f => regex.IsMatch(f.Name)) + .OrderBy(f => f.Name); + Values = fields.Select(field => (double)field.GetValue(obj)); + } +} + +public class FlattenSeasonality +{ + public IEnumerable Values { get; set; } + public FlattenSeasonality(string name, Nursing obj) + { + var regex = new Regex($"Month[\\d]{{2}}{name}", RegexOptions.IgnoreCase); + Type t = typeof(Nursing); + var fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance) + .Where(f => regex.IsMatch(f.Name)) + .OrderBy(f => f.Name); + Values = fields.Select(field => (byte)field.GetValue(obj)); + } +} \ No newline at end of file diff --git a/PayPeriod query.linq b/PayPeriod query.linq new file mode 100644 index 0000000..821d87e --- /dev/null +++ b/PayPeriod query.linq @@ -0,0 +1,81 @@ + + + 40766b24-ff74-431b-b387-6c221ede77cf + true + p3121-sql-02.sdt.local + jazz prd UNC 20180206.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +(from fact in FactPayrollSampledPayPeriods + join payperiod in DimPayPeriods on fact.PayPeriodID equals payperiod.PayPeriodID + join paycode in DimPayCodeGroups on fact.PayCodeGroupID equals paycode.PayCodeGroupID + join prodclass in DimProductiveClasses on paycode.ProductiveClassID equals prodclass.ProductiveClassID + join department in DimDepartments on fact.DepartmentID equals department.DepartmentID + where prodclass.Name == "Productive" + && payperiod.PeriodEndCalendarDate < DateTime.Now + select new { fact.DepartmentID, fact.PayPeriodID, payperiod.PeriodEndCalendarDate, payperiod.PeriodStartCalendarDate }) + .GroupBy(r => r.DepartmentID, (key, grp) => + new + { + DepartmentID = key, + data = grp.Select(g => + new + { + g.PayPeriodID, + g.PeriodEndCalendarDate, + g.PeriodStartCalendarDate + }).Distinct().OrderByDescending(g => g.PeriodEndCalendarDate).Take(6) + }) \ No newline at end of file diff --git a/Pokemon API.linq b/Pokemon API.linq new file mode 100644 index 0000000..5c888d6 --- /dev/null +++ b/Pokemon API.linq @@ -0,0 +1,65 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + System.Dynamic + + +var client = new RestClient(); +client.BaseUrl = new Uri(@"http://pokeapi.co/api/v2/pokemon?limit=999"); +RestRequest request = new RestRequest(); +request.Method = Method.GET; +dynamic content = JsonConvert.DeserializeObject(client.Execute(request).Content); +((object)content).Dump(); +object name = MyExtensions.IsPropertyExist(content, "forms") ? content.forms[0].name : null; +if (name != null) name.Dump(); \ No newline at end of file diff --git a/Random Color Hex Value.linq b/Random Color Hex Value.linq new file mode 100644 index 0000000..4b5165c --- /dev/null +++ b/Random Color Hex Value.linq @@ -0,0 +1,57 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var rand = new Random(); +var color = $"#{(0x1000000 + (rand.Next()) * 0xffffff):X4}".Substring(0, 7); +color.Dump(); \ No newline at end of file diff --git a/ScoreDimensions.linq b/ScoreDimensions.linq new file mode 100644 index 0000000..f650c7a --- /dev/null +++ b/ScoreDimensions.linq @@ -0,0 +1,143 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + jazz tst Grady 20191107.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var test = (from sd in ScoreDimensions + select new StarterSetAdHocScoreDimensionInfo + { + DimensionGUID = sd.DimensionGUID, + FriendlyName = sd.FriendlyName, + GlobalID = sd.GlobalID + }).ToList(); + test.OrderByDescending(t => t.MDXMemberName).Dump(); +} + +// Define other methods and classes here + +public class StarterSetAdHocScoreDimensionInfo +{ + public Guid DimensionGUID { get; set; } + public string FriendlyName { get; set; } + public string GlobalID { get; set; } + public string AttributeId { get; set; } + public string MDXMemberID { get; set; } + public bool IsRollup { get; set; } + internal Regex ServiceLineRegex = new Regex(@"^Service Line (\d)$", RegexOptions.IgnoreCase); + public bool ServiceLineRegexIsMatch => ServiceLineRegex.IsMatch(FriendlyName); + + public string MDXMemberName + { + get + { + try + { + return AnalysisServicesUtils.GetHierarchyMDXName("Patient Encounter", + ServiceLineRegex.IsMatch(FriendlyName) && IsRollup + ? $"{ServiceLineRegex.Replace(FriendlyName, "Service Line Rollup ${1}")}" + : $"{FriendlyName}{(IsRollup ? " Rollup" : "")}"); + } + catch (Exception) + { + return string.Empty; + } + } + } + + internal string Name => $"Patient Encounter - {FriendlyName}{(IsRollup ? " Rollup" : "")}"; + + internal StarterSetAdHocScoreDimensionInfo() + { + MDXMemberID = string.Empty; + IsRollup = false; + } + +} + +public class AnalysisServicesUtils +{ + public static string GetHierarchyMDXName(string aDimensionName, string aHierarchyName) + { + var s = "[{0}].[{1}]"; + + return String.Format(s, GetASFriendlyName(aDimensionName), GetASFriendlyName(aHierarchyName)); + } + + public static string GetASFriendlyName(string aStr, bool aTrim = true) + { + //Invalid characters --> . , ; ' ` : / \ * | ? " & % $ ! + = ( ) [ ] { } + //Take out white space + var returnStr = System.Text.RegularExpressions.Regex.Replace(aStr, @"[\.,;'`:/\\\*\|\?""&%\$!\+=\(\)\[\]{}]", ""); + + if (aTrim) returnStr = returnStr.Trim(); + + //Replace reserved name + if (returnStr.Equals("Name", StringComparison.OrdinalIgnoreCase)) returnStr = "Name_"; + if (returnStr.Equals("Measures", StringComparison.OrdinalIgnoreCase)) returnStr = "Measures_"; + if (returnStr.Equals("ID", StringComparison.OrdinalIgnoreCase)) returnStr = "ID_"; + if (returnStr.Equals("Key", StringComparison.OrdinalIgnoreCase)) returnStr = "Key_"; + return returnStr; + } + + + + +} diff --git a/Snapshot classes testing.linq b/Snapshot classes testing.linq new file mode 100644 index 0000000..f78a47b --- /dev/null +++ b/Snapshot classes testing.linq @@ -0,0 +1,194 @@ + + + 6a7da5d6-5345-4fd8-9ca6-ab567ac5f639 + true + D0014-SQL-01.sdt.local + jazz tst UNC 20190716.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var Departments = (from dept in DeptPayPeriodSummaries + select new DeptPayPeriodSummary(dept)) + .ToList() + .GroupBy(d => d.DepartmentID, (key, dx) => new { key, data = dx.OrderBy(d => d.PeriodEndDate).ToList() }) + .Where(d => d.data.Sum(x => x.TotalVariance) != 0.0d) + .Select(grp => new DeptInfo(grp.data)); + Departments.Dump("Raw List"); + var top5 = Departments + .OrderBy(d => d.latest_total_variance) + .ThenBy(d => d.latest_pay_variance) + .ThenBy(d => d.latest_flex_variance) + .Take(5).ToList(); + var bottom5 = Departments + .OrderByDescending(d => d.latest_total_variance) + .ThenByDescending(d => d.latest_pay_variance) + .ThenByDescending(d => d.latest_flex_variance) + .Take(5).ToList(); + bottom5.Dump("Bottom5"); + top5.Dump("top5"); + var departments = (top5.Union(bottom5).Distinct()) + .OrderBy(d => d.latest_total_variance).ToList(); + departments.Dump("departments"); +} + +// Define other methods and classes here +public partial class DeptPayPeriodSummary +{ + public int DepartmentID { get; set; } + public int PayPeriodID { get; set; } + public string Department { get; set; } + public DateTime PeriodStartDate { get; set; } + public DateTime PeriodEndDate { get; set; } + public double ActualHours { get; set; } + public double ActualDollars { get; set; } + public double ActualUOS { get; set; } + public double TargetHours { get; set; } + public double TargetDollars { get; set; } + public double TargetUOS { get; set; } + public double VarianceHours { get; set; } + public double VarianceDollars { get; set; } + public double VarianceUOS { get; set; } + public double ActualPayRate => MathExtensions.DivideBy((double)ActualDollars, ActualHours); + public double TargetPayRate => MathExtensions.DivideBy((double)TargetDollars, TargetHours); + public double VariancePayRate => TargetPayRate - ActualPayRate; + public double PayRateVariance => VariancePayRate * ActualHours; + public double FlexVariance => VarianceHours * TargetPayRate; + public double TotalVariance => PayRateVariance + FlexVariance; + public double VariancePayDollars => (ActualPayRate - TargetPayRate) * ActualHours; + public double VarianceFlexDollars => TargetPayRate * VarianceHours; + + public DeptPayPeriodSummary(LINQPad.User.DeptPayPeriodSummary dept) + { + DepartmentID = dept.DepartmentID; + PayPeriodID = dept.PayPeriodID; + Department = dept.Department; + PeriodStartDate = dept.PeriodStartDate; + PeriodEndDate = dept.PeriodEndDate; + ActualHours = dept.ActualHours; + ActualDollars = dept.ActualDollars; + ActualUOS = dept.ActualUOS; + TargetHours = dept.TargetHours; + TargetDollars = dept.TargetDollars; + TargetUOS = dept.TargetUOS; + VarianceHours = dept.VarianceHours; + VarianceDollars = dept.VarianceDollars; + VarianceUOS = dept.VarianceUOS; + } + +} + +public class DeptInfo +{ + public string hyperlink => ""; + + internal int deptid { get; set; } + public string name { get; set; } + internal double latest_total_variance { get; set; } + internal double latest_pay_variance { get; set; } + internal double latest_flex_variance { get; set; } + public string total_variance => $"{latest_total_variance:C}"; + public string pay_variance => $"{latest_pay_variance:C}"; + public string flex_variance => $"{latest_flex_variance:C}"; + public string six_period_total_chart { get; set; } + public string six_period_pay_chart { get; set; } + public string six_period_flex_chart { get; set; } + public IEnumerable totalGraph { get; set; } + public IEnumerable payGraph { get; set; } + public IEnumerable flexGraph { get; set; } + public int graphMin { get; set; } + public int graphMax { get; set; } + public string total_color => latest_total_variance >= 0 ? "positive" : "negative"; + public string pay_color => latest_pay_variance >= 0 ? "positive" : "negative"; + public string flex_color => latest_flex_variance >= 0 ? "positive" : "negative"; + + public DeptInfo(List department) + { + deptid = department.First().DepartmentID; + name = department.First().Department; + latest_total_variance = department.Sum(d => d.TotalVariance); + latest_pay_variance = department.Sum(d => d.PayRateVariance); + latest_flex_variance = department.Sum(d => d.FlexVariance); + totalGraph = department.Select(d => Convert.ToInt32(d.TotalVariance)); + payGraph = department.Select(d => Convert.ToInt32(d.PayRateVariance)); + flexGraph = department.Select(d => Convert.ToInt32(d.FlexVariance)); + graphMin = Math.Min(Math.Min(totalGraph.Min(), payGraph.Min()), flexGraph.Min()); + graphMax = Math.Max(Math.Max(totalGraph.Max(), payGraph.Max()), flexGraph.Max()); + } + + public DeptInfo(int departmentId, string deptName, double total, double pay, double flex) + { + deptid = departmentId; + name = deptName; + latest_total_variance = total; + latest_pay_variance = pay; + latest_flex_variance = flex; + } + + internal string GetLinkUrlPath() => $"/PR/DepartmentProductivity.aspx?deptid={deptid}&mode=payperiod"; + + public bool Equals(DeptInfo x, DeptInfo y) + { + if (object.ReferenceEquals(x, y)) return true; + if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null)) return false; + return (x.deptid == y.deptid); + } + + public int GetHashCode(DeptInfo obj) + { + return obj.GetHashCode(); + } +} \ No newline at end of file diff --git a/Sole Hope/Sole Hope Inventory Complex.linq b/Sole Hope/Sole Hope Inventory Complex.linq new file mode 100644 index 0000000..988e55f --- /dev/null +++ b/Sole Hope/Sole Hope Inventory Complex.linq @@ -0,0 +1,305 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + <RuntimeDirectory>\System.Data.Entity.Design.dll + <RuntimeDirectory>\System.Data.Entity.dll + LINQtoCSV + LINQtoCSV + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.Dynamic + System.Globalization + System.IO.Compression + System.Data.Entity.Design.PluralizationServices + + +private PluralizationService ps => PluralizationService.CreateService(new CultureInfo("en-US")); + +void Main() +{ + var testExpando = new List(); + var meds = new List(); + var inputFileDescription = new CsvFileDescription + { + SeparatorChar = '\t', // tab delimited + FirstLineHasColumnNames = false, // no column names in first record + FileCultureName = "en-US" // use formats used in The Netherlands + }; + var cc = new CsvContext(); + var path = @"C:\Users\tlamb\Downloads\"; + var files = new[] { + @"Outreach - Monthly Inventory Records - Inventory - March.tsv", + @"Outreach - Monthly Inventory Records - Inventory - April.tsv", + @"Outreach - Monthly Inventory Records - Inventory - May.tsv", + @"Outreach - Monthly Inventory Records - Inventory - June.tsv" + }.ToList(); + var nextmonth = new DateTime(2019, 2, 1); + files.ForEach(inventory => + { + nextmonth = nextmonth.AddMonths(1); + var monthData = cc.Read(Path.Combine(path, inventory), inputFileDescription); + var data = ConvertToDataRow(ConvertMyDataRow(monthData, nextmonth).ToList()).ToList(); + meds.AddRange(data); + }); + + var medBrands = meds + .Select(m => new PropDef(m)) + .Distinct(new NameBrandComparer()) + .OrderBy(m => m.name).ThenBy(m => m.type) + .Select((m, i) => new + { + Id = i + 1, + Medication = m.name, + Brand = m.type, + Minimum = Math.Max(m.inventory.StartQty, 10), + m.inventory.Dosage, + Unit = m.inventory.container, //ps.Singularize(m.inventory.container.Trim("() ".ToCharArray())), + Package = Regex.Replace(m.inventory.PerBox, @"[^\d]*", ""), + Per = m.inventory.Per, //ps.Singularize(m.inventory.Unit.Trim("() ".ToCharArray())), + Purchased = m.inventory.Purchased + }) + .ToList(); + + medBrands.Dump(); + foreach (var m in meds) + { + var mbx = medBrands.FirstOrDefault(mb => m.Medicine.Trim() == mb.Medication && m.MedicineBrand.Trim() == mb.Brand); + if (mbx != null) + { + m.MedicineID = mbx.Id; + } + else + { + m.Dump(); + } + }; + meds.GroupBy(m => m.MedicineID) + .Select(grp => grp.Last()) + .OrderBy(m => m.MedicineID) + .ThenBy(m => m.Expiry) + .ThenBy(m => m.InvDate) + .Dump(); +} + +// Define other methods and classes here +internal IEnumerable ConvertMyDataRow(IEnumerable data, DateTime month) +{ + var groupData = data.SelectMany(dr => dr.ToList()) + .GroupBy(t => t.LineNbr) + .Select(t => new { Key = t.Key - 2, Values = t.ToList().Select(v => v.Value).ToArray() }); + //groupData.Dump("groupData"); + var properties = groupData.Where(d => d.Key < 0) + .SelectMany(d => d.Values.Select(v => Regex.Replace(v, @"[\s()]", "") + //.Replace("LastMonthsFinalQuantity", "Start_Quantity") + .Replace("StartingQuantityBeginningofMonth", "StartQuantity") + .Replace("StartingQuantityBeginningofCurrentMonth", "StartQuantity") + .Replace("FinalQuantityEndofMonth", "FinalQuantity") + .Replace("FinalQuantityEndofCurrentMonth", "FinalQuantity") + .Replace("MedicationTotalStartQuantity", "MedicationTotal")).ToList()).ToArray(); + //properties.Dump("properties"); + var medication = string.Empty; + var expandoData = groupData.Where(d => d.Key >= 0) + .Select((t, j) => + { + dynamic expando = new ExpandoObject(); + AddProperty(expando, "MedicineID", j); + AddProperty(expando, "InvDate", month); + int i = 0; + t.Values.ToList().ForEach(d => + { + var property = properties[i] + .Replace("Medication", "Medicine"); + if (property == "Medicine") + { + if (string.IsNullOrEmpty(d)) + { + d = medication; + } + medication = d; + } + AddProperty(expando, property, d ?? string.Empty); + i++; + }); + return expando; + }); + return expandoData; +} + +internal IEnumerable ConvertToDataRow(List data) +{ + var newData = + data.Select(d => (d as IDictionary)) + .Select(d => + { + var dr = new Inventory(); + d.Keys.ToList().ForEach(k => + { + var value = d[k]; + var name = Regex.Replace(k, "[^A-Za-z]", ""); + PropertyInfo prop = dr.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (null != prop && prop.CanWrite) + { + prop.SetValue(dr, value, null); + } + }); + return dr; + }); + return newData; +} + +// Define other methods and classes here +internal class MyDataRow : List, IDataRow +{ +} + +public static void AddProperty(ExpandoObject expando, string propertyName, object propertyValue) +{ + // ExpandoObject supports IDictionary so we can extend it like this + var expandoDict = expando as IDictionary; + if (expandoDict.ContainsKey(propertyName)) + expandoDict[propertyName] = propertyValue; + else + expandoDict.Add(propertyName, propertyValue); +} + +public class Inventory +{ + internal Regex regex = new Regex(@"\(?(Tube|Bottle|Tablet|Capsule|Lancet|Vial|Kit)[ s]?\)?", RegexOptions.IgnoreCase); + internal string PerBox { get; set; } + internal string container => ps.Singularize(regex.Match(PerBox).Value.Trim("() ".ToCharArray())); + internal string StartQuantity { get; set; } + internal string Received { get; set; } + internal string Output { get; set; } + internal string FinalQuantity { get; set; } + internal string Notes { get; set; } + internal string ExpirationDate { get; set; } + internal string LastMonthsFinalQuantity { get; set; } + + internal PluralizationService ps => PluralizationService.CreateService(new CultureInfo("en-US")); + + public int MedicineID { get; set; } + public DateTime InvDate { get; set; } + public string Medicine { get; set; } + public string MedicineBrand { get; set; } + public string Dosage { get; set; } + public string Unit { get; set; } + public string Pkg => container != string.Empty ? PerBox.Replace(container, "").TrimEnd() : PerBox; + public string Per => ps.Singularize((string.IsNullOrEmpty(container) ? regex.Match(Unit).Value : container).Trim()); + public int StartQty => ParseStartQuantity(StartQuantity, LastMonthsFinalQuantity); + public int FinalQty => ParseFinalQuantity(FinalQuantity); + public DateTime Purchased => !Notes.StartsWith("Purchased") ? new DateTime(2018,1,1).Date + : DateTime.Parse(Regex.Replace(Notes, @"[^\d/]*", "")); + public DateTime Expiry => ParseExpiry(); + public string Note => !Notes.StartsWith("Purchased") ? Notes : string.Empty; + // public string Medication { get; set; } + internal string BrandTotal { get; set; } + internal string MedicationTotal { get; set; } + + public Inventory() + { + Medicine = string.Empty; + Dosage = string.Empty; + PerBox = string.Empty; + StartQuantity = string.Empty; + Received = string.Empty; + Output = string.Empty; + FinalQuantity = string.Empty; + ExpirationDate = string.Empty; + Notes = string.Empty; + //Medication = string.Empty; + MedicineBrand = string.Empty; + BrandTotal = string.Empty; + MedicationTotal = string.Empty; + Unit = string.Empty; + LastMonthsFinalQuantity = string.Empty; + } + + internal DateTime ParseExpiry() + { + if (string.IsNullOrEmpty(ExpirationDate)) return DateTime.MaxValue.Date; + DateTime dt; + if (!DateTime.TryParseExact(ExpirationDate, @"M/yy", null, DateTimeStyles.None, out dt)) return DateTime.MaxValue.Date; + return dt; + } + + internal Int32 ParseFinalQuantity(string FinalQuantity) + { + var result = 0; + var regex = new Regex(@"[^\d]+", RegexOptions.IgnoreCase); + try + { + result = Convert.ToInt32("0" + (string.IsNullOrEmpty(FinalQuantity) || string.IsNullOrEmpty(regex.Replace(FinalQuantity, "")) + ? "" : regex.Replace(FinalQuantity, ""))); + } + catch (Exception ex) + { + ex.Message.Dump(); + } + return result; + } + + internal Int32 ParseStartQuantity(string StartQuantity, string LastMonthsFinalQuantity) + { + var result = 0; + var regex = new Regex(@"[^\d]+", RegexOptions.IgnoreCase); + try + { + result = Convert.ToInt32("0" + (!string.IsNullOrEmpty(regex.Replace(StartQuantity, "")) + ? regex.Replace(StartQuantity, "") + : !string.IsNullOrEmpty(regex.Replace(LastMonthsFinalQuantity, "")) + ? regex.Replace(LastMonthsFinalQuantity, "") : "")); + } + catch (Exception ex) + { + ex.Message.Dump(); + } + return result; + } +} + +public class PropDef +{ + public string name { get; set; } + public string type { get; set; } + public Inventory inventory { get; set; } + + public PropDef(string a, System.Type b) + { + name = a; + type = b.Name; + } + public PropDef(Inventory inv) + { + name = inv.Medicine == string.Empty ? inv.MedicineBrand.Trim() : inv.Medicine.Trim(); + type = inv.Medicine == string.Empty ? string.Empty : inv.MedicineBrand.Trim(); + inventory = inv; + } +} + +public class NameBrandComparer : IEqualityComparer +{ + public bool Equals(PropDef med1, PropDef med2) + { + if (med1 == null && med2 == null) return true; + else if (med1 == null || med2 == null) return false; + else if (med1.inventory != null && med2.inventory != null) + { + if (med1.name == med2.name && med1.type == med2.type && med1.inventory.Purchased == med2.inventory.Purchased) return true; + else return false; + } + else if (med1.name == med2.name && med1.type == med2.type) return true; + else + return false; + } + + public int GetHashCode(PropDef med) + { + return $"{med.name}{med.type}".GetHashCode(); + } +} + diff --git a/Sole Hope/Sole Hope Inventory Normalized.linq b/Sole Hope/Sole Hope Inventory Normalized.linq new file mode 100644 index 0000000..9492863 --- /dev/null +++ b/Sole Hope/Sole Hope Inventory Normalized.linq @@ -0,0 +1,237 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + AutoMapper + AutoMapper + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + AutoMapper.Configuration.Annotations + static UserQuery + + +private IDResolver idResolver = new IDResolver(); + +protected MapperConfiguration config { get; } = new MapperConfiguration(cfg => +{ + cfg.AddMaps(Assembly.GetExecutingAssembly()); + cfg.Advanced.AllowAdditiveTypeMapCreation = true; + cfg.ValidateInlineMaps = false; +}); + +void Main() +{ + + NameBrandExpiryComparer nameBrandExpiryEqC = new NameBrandExpiryComparer(); + NameBrandComparer nameBrandEqC = new NameBrandComparer(); + + Mapper.Reset(); + IMapper mapper = new Mapper(config); + mapper.ConfigurationProvider.CompileMappings(); + mapper.ConfigurationProvider.AssertConfigurationIsValid(); + + var path = @"C:\Users\Tlamb\Downloads"; + var json = "medications.json"; + var data = LoadFile(Path.Combine(path, json)); + + var meds = mapper.Map>(data.records); + var medBrandList = meds.Distinct(nameBrandEqC) + .OrderBy(m => m.Name).ThenBy(m => m.Brand) + .Select((m, i) => mapper.Map(m, opt => opt.Items["id"] = i)) + .ToList(); + medBrandList.Dump("MedBrands"); + + var withLabels = medBrandList.Select(m => mapper.Map(m, opt => opt.Items["id"] = m.MedicineID)); //new MedBrandLabel(m)); + withLabels.Dump("MedBrands with Labels"); + + var medList = meds.Distinct(nameBrandExpiryEqC) + .Join(medBrandList + , exp => new { exp.Name, exp.Brand } + , key => new { key.Name, key.Brand }, + (exp, key) => new MedInventory + { + MedicineID = key.MedicineID, + Start = exp.Start, + Expiry = exp.Expiry, + }) + .OrderBy(m => m.MedicineID).ThenBy(m => m.Expiry) + .ToList(); + medList.Dump("Med List"); + var medInv = medList.Select(ml => mapper.Map(ml, opt => opt.Items["medBrands"] = withLabels.ToDictionary(key => key.MedicineID, label => label.Label))); + medInv.Dump("Med Inventory"); + + meds.OrderBy(m => m.Name).ThenBy(m => m.Brand).ThenBy(m => m.Expiry).Dump(); + +} + +public RootObject LoadFile(string fileName) +{ + var jsonFile = File.ReadAllText(fileName); + return JsonConvert.DeserializeObject(jsonFile); +} + +// Define other methods and classes here + +public class NameBrandExpiryComparer : IEqualityComparer +{ + public bool Equals(Medication med1, Medication med2) + { + if (med1 == null && med2 == null) return true; + else if (med1 == null || med2 == null) return false; + else if (med1.Name == med2.Name && med1.Brand == med2.Brand && med1.Expiry == med2.Expiry) return true; + else + return false; + } + + public int GetHashCode(Medication med) + { + return $"{med.Name}{med.Brand}{med.Expiry:MMddyyyy}".GetHashCode(); + } +} + +public class NameBrandComparer : IEqualityComparer +{ + public bool Equals(Medication med1, Medication med2) + { + if (med1 == null && med2 == null) return true; + else if (med1 == null || med2 == null) return false; + else if (med1.Name == med2.Name && med1.Brand == med2.Brand) return true; + else + return false; + } + + public int GetHashCode(Medication med) + { + return $"{med.Name}{med.Brand}".GetHashCode(); + } +} + +[AutoMap(typeof(Record))] +public class Medication +{ + [SourceMember(nameof(Record.field_48_raw))] + public int MedicineID { get; set; } + [SourceMember(nameof(Record.field_49_raw))] + public string Name { get; set; } + [SourceMember(nameof(Record.field_50_raw))] + public string Brand { get; set; } + [SourceMember(nameof(Record.field_51_raw))] + public int Start { get; set; } + [SourceMember(nameof(Record.field_55_raw))] + public int Minimum { get; set; } + [SourceMember(nameof(Record.field_57_raw))] + public Field57Raw field57 { get; set; } + public DateTime Expiry => field57?.iso_timestamp ?? DateTime.MaxValue; + [Ignore] + public bool NeedsReorder => (Start < Minimum) || (Expiry <= DateTime.Now); +} + +[AutoMap(typeof(Medication))] +public class MedBrand +{ + [ValueResolver(typeof(IDResolver))] + public int MedicineID { get; set; } + public string Name { get; set; } + public string Brand { get; set; } + public int Minimum { get; set; } + [Ignore] + public string Dosage { get; set; } + [Ignore] + public int Package { get; set; } + [Ignore] + public string Per { get; set; } + [Ignore] + public string Unit { get; set; } + + public MedBrand() + { + Minimum = 10; + Dosage = "50mg"; + Unit = "Tablet"; + Package = 250; + Per = "Bottle"; + } + +} + +[AutoMap(typeof(MedBrand))] +public class MedBrandLabel : MedBrand +{ + [Ignore] + public string Label => $"{Name} {Brand} {Dosage} {Package} {Per} / {Unit}"; +} + +public class MedInventory +{ + public int MedicineID { get; set; } + public int Start { get; set; } + public DateTime Expiry { get; set; } + public bool NeedsReorder => Expiry <= DateTime.Now; +} + +[AutoMap(typeof(MedInventory))] +public class MedInvLabel : MedInventory +{ + [ValueResolver(typeof(BrandResolver))] + public string MedicationBrand { get; set; } + [Ignore] + public string Label => $"{MedicationBrand} {Expiry:MM/dd/yyyy}"; +} + +public class Field57Raw +{ + public string date { get; set; } + public string date_formatted { get; set; } + public string hours { get; set; } + public string minutes { get; set; } + public string am_pm { get; set; } + public object unix_timestamp { get; set; } + public DateTime iso_timestamp { get; set; } + public string timestamp { get; set; } + public int time { get; set; } +} + +public class Record +{ + public string id { get; set; } + public int field_48_raw { get; set; } + public string field_49_raw { get; set; } + public string field_50_raw { get; set; } + public int field_51_raw { get; set; } + public int field_52_raw { get; set; } + public int field_53_raw { get; set; } + public int field_54_raw { get; set; } + public int field_55_raw { get; set; } + public bool field_56_raw { get; set; } + public Field57Raw field_57_raw { get; set; } + public string field_58_raw { get; set; } + public string field_63_raw { get; set; } +} + +public class RootObject +{ + public List records { get; set; } +} + +public class IDResolver : IValueResolver +{ + public int Resolve(object source, object destination, int id, ResolutionContext context) + { + id = (int)context.Items["id"]; + return id; + } +} + +public class BrandResolver : IValueResolver +{ + public string Resolve(MedInventory source, object destination, string label, ResolutionContext context) + { + label = ((Dictionary)context.Items["medBrands"])[source.MedicineID]; + return label; + } +} \ No newline at end of file diff --git a/Sole Hope/SoleHope Inventory refactoring.linq b/Sole Hope/SoleHope Inventory refactoring.linq new file mode 100644 index 0000000..c5ef252 --- /dev/null +++ b/Sole Hope/SoleHope Inventory refactoring.linq @@ -0,0 +1,275 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + <RuntimeDirectory>\System.Data.Entity.Design.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + LINQtoCSV + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + LINQPad.Extensibility.DataContext.DbSchema + LINQtoCSV + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.Globalization + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.Data.Entity.Design.PluralizationServices + + +private static PluralizationService ps => PluralizationService.CreateService(new CultureInfo("en-US")); + +void Main() +{ + var path = @"C:\Users\tlamb\downloads"; + var newPath = @"C:\Users\tlamb\downloads\Solehope 190705"; + var file = "medical inventory July 5 2019.2.csv"; + var filepath = Path.Combine(path, file); + + CsvFileDescription inputFileDescription = new CsvFileDescription + { + SeparatorChar = ',', + FirstLineHasColumnNames = true, + IgnoreUnknownColumns = true + }; + + CsvFileDescription outputFileDescription = new CsvFileDescription + { + SeparatorChar = ',', + FirstLineHasColumnNames = true + }; + + CsvContext cc = new CsvContext(); + IEnumerable medications; + IEnumerable inventory; + IEnumerable intake; + + var meds = cc.Read(filepath, inputFileDescription).ToList(); + meds.Dump(file); + + medications = meds.ConvertAll(med => (MedicationOut)med); + inventory = meds.ConvertAll(med => (Inventory)med); + inventory = inventory.OrderBy(i => i.Medication) + .Select((i, idx) => { i.InventoryId = idx.ToString(); return i; }); + intake = meds.ConvertAll(med => (Intake)med); + intake = intake + .Join(inventory, x => x.MedicationId, inv => inv.MedicationId, (x, inv) => new { intake = x, inv }).ToList() + .ConvertAll(u => { u.intake.InventoryId = u.inv.InventoryId; return u.intake; }); + + var updates = cc.Read(Path.Combine(@"C:\Users\tlamb\downloads\Solehope 190819", "intake2.csv"), inputFileDescription).ToList() + .Join(inventory, x => x.InventoryId, inv => inv.InventoryId, (x, inv) => new { intake = x, inv }).ToList() + .ConvertAll(u => { u.intake.MedicationId = u.inv.MedicationId; return u.intake; }); + + newPath.Dump("New Path"); + medications.Dump("Medications"); + inventory.Dump("Inventory"); + intake.Dump("Intake - from Medications"); + updates.Dump("Updates"); + + file = "medication.csv"; + filepath = Path.Combine(newPath, file); + cc.Write(medications, filepath, outputFileDescription); + file = "inventory.csv"; + filepath = Path.Combine(newPath, file); + cc.Write(inventory, filepath, outputFileDescription); + file = "intake.csv"; + filepath = Path.Combine(newPath, file); + cc.Write(intake, filepath, outputFileDescription); + file = "updates.csv"; + filepath = Path.Combine(newPath, file); + cc.Write(updates, filepath, outputFileDescription); +} + +// Define other methods and classes here + +public class Med +{ + public string Id { get; set; } + + public string Type { get; set; } + + [CsvColumn(Name = "Medication")] + public string MedicationStr { get; set; } + internal string Medications => box.Match(MedicationStr.Trim()).Success ? box.Replace(MedicationStr.Trim(), "$1").Trim() : MedicationStr.Trim(); + + public string Strength { get; set; } + + [CsvColumn(Name = "Quantity")] + public string Start { get; set; } + internal int StartCnt => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(Start) ? "0" : Start, "")); + + [CsvColumn(Name = "Minimum")] + public string MinimumStr { get; set; } + internal int MinimumCnt => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(MinimumStr) ? "0" : MinimumStr, "")); + + public string Unit { get; set; } + + public string Package { get; set; } + + [CsvColumn(Name = "Number")] + public string NumberStr { get; set; } + internal int NumberCnt => box.Match(MedicationStr.Trim()).Success ? Convert.ToInt32(box.Replace(MedicationStr.Trim(), "$2")) + : Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(NumberStr) ? "0" : NumberStr, "")); + + [CsvColumn(Name = "Expiration Date")] + public string Expiry { get; set; } + internal DateTime ExpiryDate => GetDateFromString(Expiry); + + internal string Form => string.IsNullOrEmpty(Package) ? "" + : Package.Trim() == "Tube/Cream" ? "Cream" : ps.Singularize(Package.Trim()); + internal string UnitOut => !string.IsNullOrEmpty(UnitNoBox) + ? ps.Singularize(UnitNoBox) + : string.IsNullOrEmpty(Package) + ? string.Empty + : Package.Trim() == "Tube/Cream" + ? "Tube" + : string.Empty; + + public string Label => $"{Medications} {Strength} {Form} {NumberCnt} / {UnitOut}"; + + internal string UnitNoBox => box.Match(MedicationStr.Trim()).Success ? "Box" : Unit?.Trim() ?? ""; + + internal Regex regex = new Regex(@"[^\d]"); + internal Regex date = new Regex(@"([\d]{1,2})/([\d]{1,2})/([\d]{1,4})"); + internal Regex shortDate = new Regex(@"([\d]{1,2})/([\d]{1,2})"); + internal Regex box = new Regex(@"^(\D*)([\d]*)/Box$"); + + internal DateTime GetDateFromString(string theDate) + { + DateTime result = DateTime.MaxValue; + DateTime work; + if (string.IsNullOrEmpty(theDate) || theDate == "0/0") + work = result; + else if (date.IsMatch(theDate)) + work = Convert.ToDateTime(theDate); + else if (shortDate.IsMatch(theDate)) + work = Convert.ToDateTime(shortDate.Replace(theDate, "$1/5/$2")); + else + work = result; + work = new DateTime(work.Year, work.Month, DateTime.DaysInMonth(work.Year, work.Month)); + return work; + } + +} + +public class MedicationOut +{ + public string Id { get; set; } + public string Type { get; set; } + public string Medication { get; set; } + public int Minimum { get; set; } + public string Strength { get; set; } + public string Form { get; set; } + public int Number { get; set; } + public string Unit { get; set; } + public string Label { get; internal set; } + + public static explicit operator MedicationOut(Med med) + { + return new MedicationOut + { + Id = med.Id, + Type = med.Type, + Medication = med.Medications, + Minimum = med.MinimumCnt, + Strength = med.Strength ?? "", + Form = med.Form, + Number = med.NumberCnt, + Unit = !string.IsNullOrEmpty(med.UnitNoBox) + ? ps.Singularize(med.UnitNoBox) + : string.IsNullOrEmpty(med.Package) + ? string.Empty + : med.Package.Trim() == "Tube/Cream" + ? "Tube" + : string.Empty, + Label = med.Label + }; + } +} + +public class Inventory +{ + public string MedicationId { get; set; } + public string InventoryId { get; set; } + public string Medication { get; set; } + public int Start => 0; + public string Label { get; internal set; } + public string Note { get; set; } + + public static explicit operator Inventory(Med med) + { + return new Inventory + { + MedicationId = med.Id, + Medication = med.Medications, + Label = med.Label, + Note = string.Empty + }; + } +} + +public class Intake +{ + public string MedicationId { get; set; } + public string InventoryId { get; set; } + public string Medication { get; set; } + public int Received { get; set; } + public DateTime Date { get; set; } + public DateTime Expiry { get; set; } + internal string MedLabel { get; set; } + public string Label => $"({Received}) {MedLabel}"; + + public static explicit operator Intake(Med med) + { + return new Intake + { + MedicationId = med.Id, + Medication = med.Medications, + Received = med.StartCnt, + Date = new DateTime(2019, 7, 5), + Expiry = med.ExpiryDate, + MedLabel = med.Label + }; + } +} \ No newline at end of file diff --git a/Sole Hope/SoleHopeInventory.linq b/Sole Hope/SoleHopeInventory.linq new file mode 100644 index 0000000..1a34062 --- /dev/null +++ b/Sole Hope/SoleHopeInventory.linq @@ -0,0 +1,536 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + <RuntimeDirectory>\System.Data.Entity.Design.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + LINQtoCSV + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + LINQtoCSV + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.Dynamic + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.Data.Entity.Design.PluralizationServices + System.Globalization + + +void Main() +{ + IEnumerable testExpando; + var inputFileDescription = new CsvFileDescription + { + SeparatorChar = '\t', // tab delimited + FirstLineHasColumnNames = false, // no column names in first record + FileCultureName = "en-US" // use formats used in The Netherlands + }; + var outputFileDescription = new CsvFileDescription + { + SeparatorChar = ',', // tab delimited + FirstLineHasColumnNames = true, // no column names in first record + EnforceCsvColumnAttribute = true, + FileCultureName = "en-US" // use formats used in The Netherlands + }; + var cc = new CsvContext(); + var path = @"C:\Users\tlamb\Downloads\"; + var files = new[] { + @"Outreach - Monthly Inventory Records - Inventory March.tsv", + @"Outreach - Monthly Inventory Records - Inventory - April.tsv", + @"Outreach - Monthly Inventory Records - Inventory - May.tsv", + @"Outreach - Monthly Inventory Records - Inventory - June.tsv" + }.ToList(); + var nextmonth = new DateTime(2019, 2, 1); + var productList = new List(); + var purchaseSummary = new List(); + var orderSummary = new List(); + files.ForEach(inventory => + { + nextmonth = nextmonth.AddMonths(1); + var monthData = cc.Read(Path.Combine(path, inventory), inputFileDescription); + testExpando = ConvertMyDataRow(monthData); + var products = testExpando.Select(o => new Product(o as ExpandoObject, nextmonth)).ToList(); + var purchases = testExpando.Select(o => new Purchase(o as ExpandoObject, nextmonth)).Where(p => p.Rcvd != 0).ToList(); + var orders = testExpando.Select(o => new Order(o as ExpandoObject, nextmonth)).Where(o => o.Out != 0).ToList(); + productList.AddRange(products); + purchaseSummary.AddRange(purchases); + orderSummary.AddRange(orders); + }); + var medicationBrandList = productList.GroupBy(l => new { l.Medicine, l.Brand }).Select(grp => grp.First()).ToList() + .Select(mb => new MedicationBrand { Medicine = mb.Medicine, Brand = mb.Brand, Reorder = mb.MinimumRequired }); + productList.GroupBy(p => p.Medicine).OrderBy(p => p.Key).Dump("Products"); + purchaseSummary.Dump("Purchases"); + orderSummary.Dump("Orders"); + medicationBrandList.Dump("Medications"); + var docsFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "SoleHope"); + if (!Directory.Exists(docsFolder)) + Directory.CreateDirectory(docsFolder); + cc.Write(medicationBrandList, Path.Combine(docsFolder, "MedicationBrand.csv"), outputFileDescription); + cc.Write(productList, Path.Combine(docsFolder, "Medications.csv"), outputFileDescription); + cc.Write(purchaseSummary, Path.Combine(docsFolder, "Intake.csv"), outputFileDescription); + cc.Write(orderSummary, Path.Combine(docsFolder, "Outtake.csv"), outputFileDescription); + +} + +internal IEnumerable ConvertMyDataRow(IEnumerable data) +{ + var groupData = data.SelectMany(dr => dr.ToList()) + .GroupBy(t => t.LineNbr) + .Select(t => new { Key = t.Key - 2, Values = t.ToList().Select(v => v.Value).ToArray() }); + var properties = groupData.Where(d => d.Key < 0) + .SelectMany(d => d.Values.Select(v => Regex.Replace(v, @"[\s()]", "") + .Replace("StartingQuantityBeginningofCurrentMonth", "StartQuantity") + .Replace("FinalQuantityEndofCurrentMonth", "FinalQuantity") + .Replace("MedicationTotalStartQuantity", "StartQuantity")).ToList()).ToArray(); + var medication = string.Empty; + var expandoData = groupData.Where(d => d.Key >= 0) + .Select((t, j) => + { + dynamic expando = new ExpandoObject(); + AddProperty(expando, "MedicineID", j); + int i = 0; + t.Values.ToList().ForEach(d => + { + if (properties[i] == "Medication") + { + if (string.IsNullOrEmpty(d)) + { + d = medication; + } + medication = d; + } + AddProperty(expando, properties[i], d ?? string.Empty); + i++; + }); + return expando; + }); + return expandoData; +} + +// Define other methods and classes here +internal class MyDataRow : List, IDataRow +{ +} + +public class MedicationBrand +{ + [CsvColumn(Name = "Medication", FieldIndex = 1)] + public string Medicine { get; set; } + [CsvColumn(Name = "Brand", FieldIndex = 2)] + public string Brand { get; set; } + [CsvColumn(FieldIndex = 3)] + public int Reorder {get;set;} +} + +public class Product +{ + internal string[] Row { get; set; } + [CsvColumn(Name = "MedicineID", FieldIndex = 1)] + public int index { get; set; } + internal string InvDateStr { get; set; } + public DateTime InvDate => !string.IsNullOrEmpty(InvDateStr) + ? DateTime.ParseExact(InvDateStr, "M/yy", System.Globalization.CultureInfo.InvariantCulture) + : new DateTime(2999, 12, 31); + [CsvColumn(Name = "Medication", FieldIndex = 2)] + public string Medicine { get; set; } + [CsvColumn(Name = "Brand", FieldIndex = 3)] + public string Brand { get; set; } + [CsvColumn(FieldIndex = 4)] + public string Label => string.IsNullOrEmpty(Brand) ? $"{Medicine} ({index})" : $"{Medicine} {Brand} ({index})"; + public string Dosage { get; set; } + public string Per { get; set; } + public string Unit { get; set; } + internal string StartStr { get; set; } + internal string RcvdStr { get; set; } + internal string OutStr { get; set; } + internal string FinalStr { get; set; } + [CsvColumn(Name = "StartingInventory", FieldIndex = 5)] + public int Start => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(StartStr) ? "0" : StartStr, "")); + public int Rcvd => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(RcvdStr) ? "0" : RcvdStr, "")); + public int Out => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(OutStr) ? "0" : OutStr, "")); + public int Final => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(FinalStr) ? "0" : FinalStr, "")); + [CsvColumn(FieldIndex = 6)] + public int InventoryReceived => Rcvd; + [CsvColumn(FieldIndex = 7)] + public int InventoryShipped => Out; + [CsvColumn(FieldIndex = 8)] + public int InventoryOnHand => Final; + [CsvColumn(FieldIndex = 9)] + public int MinimumRequired => Start; + [CsvColumn(FieldIndex = 10)] + public string NeedsReorder => Start == 0 ? "Yes" : "No"; + internal string ExpiryStr { get; set; } + [CsvColumn(FieldIndex = 11)] + public DateTime Expiry { get; set; } + public DateTime Purchased { get; set; } + public DateTime OrderDate => InvDate.AddMonths(1).AddDays(-1); + public string Notes { get; set; } + + internal PluralizationService ps => PluralizationService.CreateService(new CultureInfo("en-US")); + internal Regex regex = new Regex(@"[^\d]"); + + internal Product() + { + index = 0; + InvDateStr = DateTime.Today.ToString("M/yy"); + Medicine = string.Empty; + Brand = string.Empty; + Dosage = string.Empty; + Per = string.Empty; + Unit = string.Empty; + StartStr = "0"; + RcvdStr = "0"; + OutStr = "0"; + FinalStr = "0"; + Expiry = new DateTime(2018, 1, 1); + ExpiryStr = Expiry.ToString("M/yy"); + Purchased = new DateTime(2999, 12, 31); + Notes = string.Empty; + } + + public Product(int i, string[] row) + : this() + { + Row = row; + index = i + 1; + InvDateStr = row[0]; + Medicine = row[1]; + Dosage = row[2] ?? string.Empty; + Per = row[3] ?? string.Empty; + Unit = row[3] ?? string.Empty; + Unit = Unit.ToUpper().Contains("TUBE") ? "Tube" + : Unit.ToUpper().Contains("BOTTLE") ? "Bottle" + : Unit.ToUpper().Contains("VIAL") ? "Vial" + : Unit.ToUpper().Contains("TABLET") ? "Tablet" + : Unit.ToUpper().Contains("CAPSULE") ? "Capsule" + : Unit.ToUpper().Contains("LANCET") ? "Lancet" : Unit; + Per = !string.IsNullOrEmpty(Per) ? Per.Replace(Unit, "").TrimEnd("(s) ".ToCharArray()) : string.Empty; + StartStr = string.IsNullOrEmpty(row[4]) ? "0" : row[4]; + RcvdStr = string.IsNullOrEmpty(row[5]) ? "0" : row[5]; + OutStr = string.IsNullOrEmpty(row[6]) ? "0" : row[6]; + FinalStr = string.IsNullOrEmpty(row[7]) ? "0" : row[7]; + ExpiryStr = row[8]; + Notes = string.IsNullOrEmpty(row[9]) ? string.Empty : row[9]; + Expiry = !string.IsNullOrEmpty(ExpiryStr) + ? DateTime.ParseExact(ExpiryStr, "M/yy", System.Globalization.CultureInfo.InvariantCulture) + : new DateTime(2999, 12, 31); + Purchased = !string.IsNullOrEmpty(Notes) && Notes.StartsWith("Purchased") + ? DateTime.ParseExact(Notes.Substring(10), "M/d/yy", System.Globalization.CultureInfo.InvariantCulture) + : DateTime.Compare(Expiry, new DateTime(2018, 1, 1)) < 0 + ? Expiry.AddMonths(-6) : new DateTime(2018, 1, 1); + Notes = Notes.Replace($"Purchased {Purchased:M/d/yy}", ""); + } + + public Product(ExpandoObject expando, DateTime invDate) + : this() + { + InvDateStr = invDate.ToString("M/yy"); + var dictionary = expando as IDictionary; + dictionary.Keys.ToList() + .ForEach(k => + { + var value = Convert.ToString(dictionary[k]); + switch (k) + { + case "MedicineID": + index = Convert.ToInt32(value); + break; + case "Medicine": + case "Medication": + Medicine = value; + break; + case "MedicineBrand": + Brand = value; + break; + case "Dosage": + Dosage = value; + break; + case "PerBox": + Per = value; + break; + case "Unit": + Unit = ps.IsPlural(value) ? ps.Singularize(value) : value; + break; + case "Start": + case "StartQuantity": + StartStr = value; + break; + case "Received": + RcvdStr = value; + break; + case "Output": + OutStr = value; + break; + case "Final": + FinalStr = value; + break; + case "ExpirationDate": + ExpiryStr = Regex.Replace(value, @"[^\d/]", ""); + Expiry = !string.IsNullOrEmpty(ExpiryStr) + ? DateTime.ParseExact(ExpiryStr, "M/yy", System.Globalization.CultureInfo.InvariantCulture) + : new DateTime(2999, 12, 31); + break; + } + }); + if (string.IsNullOrEmpty(Unit)) + { + Unit = FindUnits(Per); + if (string.IsNullOrEmpty(Unit)) + Unit = FindUnits(Dosage); + } + } + + public string FindUnits(string unit) + { + return unit.ToUpper().Contains("TUBE") ? "Tube" + : unit.ToUpper().Contains("BOTTLE") ? "Bottle" + : unit.ToUpper().Contains("VIAL") ? "Vial" + : unit.ToUpper().Contains("TABLET") ? "Tablet" + : unit.ToUpper().Contains("CAPSULE") ? "Capsule" + : unit.ToUpper().Contains("LANCET") ? "Lancet" + : string.Empty; + } + + object ToDump() => new + { + MedicineID = index, + Medication = Medicine, + Brand, + Label, + Unit, + StartingInventory = Start, + InventoryReceived, + InventoryShipped, + InventoryOnHand, + MinimumRequired, + NeedsReorder, + Expiry = $"{Expiry.AddMonths(1).AddDays(-1):MM/dd/yy}" + }; +} + +public class Order +{ + internal string[] Row { get; set; } + [CsvColumn(Name = "MedicineID", FieldIndex = 1)] + public int index { get; set; } + internal string InvDateStr { get; set; } + public DateTime InvDate => !string.IsNullOrEmpty(InvDateStr) + ? DateTime.ParseExact(InvDateStr, "M/yy", System.Globalization.CultureInfo.InvariantCulture) + : new DateTime(2999, 12, 31); + [CsvColumn(Name = "Medication", FieldIndex = 2)] + public string Medicine { get; set; } + internal string Brand { get; set; } + [CsvColumn(FieldIndex = 3)] + public string Label => $"{Medicine} {Brand}"; + [CsvColumn(FieldIndex = 4)] + public string Customer => string.Empty; + internal string OutStr { get; set; } + [CsvColumn(Name = "Shipped", FieldIndex = 5)] + public int Out => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(OutStr) ? "0" : OutStr, "")); + [CsvColumn(Name = "Date", FieldIndex = 6)] + public DateTime OrderDate => InvDate.AddMonths(1).AddDays(-1); + + internal PluralizationService ps => PluralizationService.CreateService(new CultureInfo("en-US")); + internal Regex regex = new Regex(@"[^\d]"); + + internal Order() + { + index = 0; + InvDateStr = DateTime.Today.ToString("M/yy"); + Medicine = string.Empty; + Brand = string.Empty; + OutStr = "0"; + } + + public Order(ExpandoObject expando, DateTime invDate) + : this() + { + InvDateStr = invDate.ToString("M/yy"); + var dictionary = expando as IDictionary; + dictionary.Keys.ToList() + .ForEach(k => + { + var value = Convert.ToString(dictionary[k]); + switch (k) + { + case "MedicineID": + index = Convert.ToInt32(value); + break; + case "Medicine": + case "Medication": + Medicine = value; + break; + case "MedicineBrand": + Brand = value; + break; + case "Output": + OutStr = value; + break; + } + }); + } + + object ToDump() => new + { + MedicineID = index, + Medication = Medicine, + Brand, + Label, + Customer = "", + Shipped = Out, + Date = InvDate.AddMonths(1).AddDays(-1) + }; + +} + +public class Purchase +{ + internal string[] Row { get; set; } + [CsvColumn(Name = "MedicineID", FieldIndex = 1)] + public int index { get; set; } + internal string InvDateStr { get; set; } + public DateTime InvDate => !string.IsNullOrEmpty(InvDateStr) + ? DateTime.ParseExact(InvDateStr, "M/yy", System.Globalization.CultureInfo.InvariantCulture) + : new DateTime(2999, 12, 31); + [CsvColumn(Name = "Medication", FieldIndex = 2)] + public string Medicine { get; set; } + internal string Brand { get; set; } + [CsvColumn(FieldIndex = 3)] + public string Label => $"{Medicine} {Brand}"; + [CsvColumn(FieldIndex = 4)] + public string Supplier => string.Empty; + internal string RcvdStr { get; set; } + [CsvColumn(Name = "Received", FieldIndex = 5)] + public int Rcvd => Convert.ToInt32(regex.Replace(string.IsNullOrEmpty(RcvdStr) ? "0" : RcvdStr, "")); + internal string Notes { get; set; } + internal string ExpiryStr = ""; + internal DateTime Expiry => !string.IsNullOrEmpty(ExpiryStr) + ? DateTime.ParseExact(ExpiryStr, "M/yy", System.Globalization.CultureInfo.InvariantCulture) + : new DateTime(2999, 12, 31); + [CsvColumn(Name = "Date", FieldIndex = 6)] + public DateTime Purchased { get; set; } + + internal PluralizationService ps => PluralizationService.CreateService(new CultureInfo("en-US")); + internal Regex regex = new Regex(@"[^\d]"); + + internal Purchase() + { + index = 0; + InvDateStr = DateTime.Today.ToString("M/yy"); + Medicine = string.Empty; + Brand = string.Empty; + RcvdStr = "0"; + Purchased = new DateTime(2999, 12, 31); + } + + public Purchase(ExpandoObject expando, DateTime invDate) + : this() + { + InvDateStr = invDate.ToString("M/yy"); + Purchased = InvDate; + var dictionary = expando as IDictionary; + dictionary.Keys.ToList() + .ForEach(k => + { + var value = Convert.ToString(dictionary[k]); + switch (k) + { + case "MedicineID": + index = Convert.ToInt32(value); + break; + case "Medicine": + case "Medication": + Medicine = value; + break; + case "MedicineBrand": + Brand = value; + break; + case "Received": + RcvdStr = value; + break; + case "ExpirationDate": + ExpiryStr = Regex.Replace(value, @"[^\d/]", ""); + break; + case "Notes:": + var purchaseStr = !string.IsNullOrEmpty(value) && value.StartsWith("Purchased") + ? Regex.Replace(value, @"[^\d/]", "") + : string.Empty; + Purchased = !string.IsNullOrEmpty(purchaseStr) + ? DateTime.ParseExact(purchaseStr, "M/d/yy", System.Globalization.CultureInfo.InvariantCulture) + : DateTime.Compare(Expiry, new DateTime(2018, 1, 1)) < 0 + ? Expiry.AddMonths(-6) : new DateTime(2018, 1, 1); ; + break; + } + }); + } + + object ToDump() => new + { + MedicineID = index, + Medication = Medicine, + Brand, + Label, + Supplier = "", + Received = Rcvd, + Date = Purchased + }; +} + +public static void AddProperty(ExpandoObject expando, string propertyName, object propertyValue) +{ + // ExpandoObject supports IDictionary so we can extend it like this + var expandoDict = expando as IDictionary; + if (expandoDict.ContainsKey(propertyName)) + expandoDict[propertyName] = propertyValue; + else + expandoDict.Add(propertyName, propertyValue); +} \ No newline at end of file diff --git a/SonarQube API/Quboo Integration API.linq b/SonarQube API/Quboo Integration API.linq new file mode 100644 index 0000000..83aa44c --- /dev/null +++ b/SonarQube API/Quboo Integration API.linq @@ -0,0 +1,74 @@ + + RestSharp + RestSharp + Newtonsoft.Json + + +void Main() +{ + Score(Severity.Critical, 5, 18).Dump(); + ScoreAlt(Severity.Critical, 5, 18).Dump(); + awardPoints("jchau", Severity.Critical, 5, 18); + Score(Severity.Major, 15, 5).Dump(); + ScoreAlt(Severity.Major, 15, 5).Dump(); + awardPoints("jchau", Severity.Major, 15, 5); + Score(Severity.Major, 15, 4).Dump(); + awardPoints("jpollard", Severity.Major, 15, 4); + Score(Severity.Major, 10, 2).Dump(); + awardPoints("aschey", Severity.Major, 10, 2); + Score(Severity.Major, 10).Dump(); + awardPoints("tscanlan", Severity.Major, 10); +} + +// Define other methods and classes here + +public enum Severity +{ + Info = 1, + Minor = 2, + Major = 5, + Critical = 7, + Blocker = 10 +} + +public int Score(Severity severity, int debt, int items = 1) +{ + $"Math.Max(1, {debt} / 10 * {(int)severity}) * {items} items".Dump(); + return Math.Max(1, debt / 10 * (int)severity) * items; +} + +public int ScoreAlt(Severity severity, int debt, int items = 1) +{ + $"Math.Max(1, {debt} * {(int)severity} / 10) * {items} items".Dump(); + return Math.Max(1, debt * (int)severity / 10) * items; +} + +public void awardPoints(string playerLogin, Severity severity, int debt, int items = 1) +{ + string BaseUrl = @"https://api.quboo.io/score/generic"; + RestClient client = new RestClient(); + client.BaseUrl = new Uri(BaseUrl); + RestRequest request = new RestRequest(); + request.Method = Method.PUT; + request.AddHeader("x-quboo-access-key", "FgtzhUSwAdsf4sGpM0kzXePP"); + request.AddHeader("x-quboo-secret-key", "AwzF8dreEwkGemRS"); + request.AddHeader("Content-Type", " application/json"); + + var qubooBody = new + { + playerLogin = playerLogin, + uniqueId = Guid.NewGuid(), + description = $"Resolving {items} {debt}min {severity} items", + score = Score(severity, debt, items) + }; + request.AddJsonBody(qubooBody); + var result = client.Execute(request); + if (!result.IsSuccessful && result.ErrorMessage != null) + { + result.ErrorMessage.Dump(); + } + else + { + JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result.Content), Newtonsoft.Json.Formatting.Indented).Dump(); + } +} \ No newline at end of file diff --git a/SonarQube API/SonarQube Just Summarize Issue Counts.linq b/SonarQube API/SonarQube Just Summarize Issue Counts.linq new file mode 100644 index 0000000..b697f14 --- /dev/null +++ b/SonarQube API/SonarQube Just Summarize Issue Counts.linq @@ -0,0 +1,99 @@ + + +var newIssueList = Regex.Replace(@"Cube Engine/Strata.CubeEngine.UserDefinedFunctions +0 +Jazz AP Service/Jazz AP Service +30 +ModelCacheWebService/ModelCacheWebService +0 +OData +0 +Optimization/Strata.Optimization +0 +Strata Administrator +4 +Strata Cube Reporter/Strata.CubeReporter +0 +Strata Spoon/Strata.Spoon +0 +Strata Template Architect +0 +Strata.Base +1 +Strata.Base.Internal +0 +Strata.CS.Base +2 +Strata.CS.Jazz.ABB +252 +Strata.CS.Jazz.Biz +331 +Strata.CS.Jazz.Biz.CCI +49 +Strata.CS.Jazz.Biz.DSS.APReimbursementEngine +0 +Strata.CS.Jazz.Biz.DSS.Episodes +2 +Strata.CS.Jazz.Biz.DSS.Episodes.EpisodeDefinition +1 +Strata.CS.Jazz.Biz.DSS.Episodes.EpisodeVisualizer +3 +Strata.CS.Jazz.Biz.DSS.HPAdmin +9 +Strata.CS.Jazz.Biz.Notifications +0 +Strata.CS.Jazz.Biz.Snapshot/Properties +0 +Strata.CS.Jazz.Biz.StarterSet +43 +Strata.CS.Jazz.Dimensionality +0 +Strata.CS.Jazz.FP +0 +Strata.CS.Jazz.Ideas +0 +Strata.CS.Jazz.UI +3 +Strata.DataStudio20/Strata.DataStudio20 +0 +Strata.Entity.Base +0 +Strata.Hangfire.Service +0 +Strata.Jazz.Biz +1 +Strata.Jazz.FoolsGold.Biz +0 +Strata.Jazz.Hangfire +1 +Strata.Jazz.Hangfire.WebServices +0 +Strata.Jazz.Midas.Biz +19 +Strata.Jazz.Midas.Web +13 +Strata.Jazz.MVC +0 +Strata.Jazz.UI +0 +Strata.Jazz.Web +207 +Strata.Reporting.ExcelReporter40 +0 +Strata.Reporting.Opus +0 +Strata.Score +2 +Strata.Score.ConfigTool/Strata.Score.ConfigTool.Biz +0 +Strata.Score.DimensionEditor +0 +Strata.Score.DimensionEditor20 +0 +Strata.Score.DimensionEditor20.Biz +0 +", @"\r\n([\d]*\r\n)", "\t$1").Replace("\r\n", "\r").Split('\r') +.Where(x => !string.IsNullOrEmpty(x)) +.Select(x => new { project = x.Split('\t')[0], issues = x.Split('\t')[1] }) +.Where(x => x.issues != "0"); +newIssueList.Dump(); \ No newline at end of file diff --git a/SonarQube API/SonarQube WebService API.linq b/SonarQube API/SonarQube WebService API.linq new file mode 100644 index 0000000..743cfd1 --- /dev/null +++ b/SonarQube API/SonarQube WebService API.linq @@ -0,0 +1,1071 @@ + + Newtonsoft.Json + RestSharp + RestSharp + Newtonsoft.Json + Newtonsoft.Json.Linq + RestSharp.Authenticators + Newtonsoft.Json.Converters + System.Dynamic + System + System.Linq.Dynamic + System.Web + + +private string BaseUrl = "https://sonarqube.sdt.local"; +private Dictionary ruleDictionary; +//private DateTime BeginningOfTheYear = new DateTime(DateTime.Now.Year, 1, 1); +private static DateTime CreatedBefore = new DateTime(2020, 8, 13); +private static DateTime StartOfSprint = CreatedBefore.AddDays(1); +private static DateTime EndOfSprint = CreatedBefore.AddDays(15); +private Dictionary Parameters = new Dictionary +{ + { "projects", ""}, +// {"types","BUG,VULNERABILITY,SECURITY_HOTSPOT"}, +// {"severities","BLOCKER,CRITICAL,MAJOR"}, +// {"statuses", "OPEN,CONFIRMED,REOPENED,TO_REVIEW,IN_REVIEW"}, + {"resolutions", "FIXED"}, + {"s", "CLOSE_DATE"}, + {"languages", null}, + {"createdBefore", $"{CreatedBefore:yyyy-MM-dd}"}, + //{"createdAfter", null}, // $"{BeginningOfTheYear:yyyy-MM-dd}" + {"assignees", null} +}; + +#region Enumerations + +public string GetName(Type enumType, int value) +{ + return Enum.GetName(enumType, value); +} + +public enum SonarType +{ + BUG, + VULNERABILITY, + CODE_SMELL, + SECURITY_HOTSPOT +} + +public enum SonarSeverity +{ + BLOCKER, + CRITICAL, + MAJOR, + MINOR, + INFO +} + +public enum QubooSeverity +{ + BLOCKER = 10, + CRITICAL = 7, + MAJOR = 5, + MINOR = 2, + INFO = 1 +} + +public enum SonarResolution +{ + UNRESOLVED, + FIXED, + WONTFIX, + FALSE_POSITIVE, + REMOVED +} + +public enum SonarStatus +{ + OPEN, + TO_REVIEW, + IN_REVIEW, + REVIEWED, + REOPENED, + CONFIRMED, + RESOLVED, + CLOSED +} + +#endregion + +public Dictionary> GroupUsers = new Dictionary>(); + +void Main() +{ + RestClient client = new RestClient(); +// var projects = ListProjects(client); +// projects.Dump(); +// return; + new { CreatedBefore, StartOfSprint, EndOfSprint}.Dump("Campaign"); + PopulateUserGroups(); + var value = GetName(typeof(SonarType), (int)SonarType.BUG); + //GetJson(client, "/api/languages/list").Dump(); + //ListWebServices(client).Dump("List WebServices"); + var rules = GetRules(client) + .OrderBy(l => l.repo).ThenBy(l => l.key); + ruleDictionary = rules + .ToDictionary(r => r.key, r => $"{r.name} ({r.severity})"); + var parameters = new List { + new RestSharp.Parameter("additionalFields","_all", ParameterType.QueryString) + }; + parameters.AddRange(Parameters.Where(p => !string.IsNullOrEmpty(p.Value)) + .Select(p => new RestSharp.Parameter(p.Key, p.Value, ParameterType.QueryString))); + var issues = GetIssues(client, parameters) + .Where(i => i.closeDate >= StartOfSprint && i.closeDate <= EndOfSprint) + // .Where(i => i.closeDate >= CreatedBefore.AddDays(-14) && i.closeDate <= CreatedBefore) + ; + if (1 == 0) + { + if (parameters.Select(p => p.Name).Contains("projects")) + { + $"{parameters.First(p => p.Name == "projects").Value} ({issues.Count()} Issues)".Dump(); + } + else + { + $"{issues.Count()} Issues".Dump(); + } + } + issues + .Where(i => i.assignee != null) + .Select(i => new + { + i.severity, + i.project, + i.type, + i.status, + i.resolution, + i.assignee, + team = GetUserGroup(i.assignee), + i.debt, + i.effort, + i.closeDate, + score = Score(i.severity, i.debt) + }) + //.GroupBy(i => new {i.assignee, i.severity, i.type}, (g,d) => d) + .OrderBy(i => i.team) + .ThenBy(i => i.project) + .ThenBy(i => i.assignee) + .ThenBy(i => i.severity) + .ThenBy(i => i.type) + .Dump(); + //issues.Take(10).Dump("Dump 10 issues"); + //ReportIssues(issues); +} + +public int Score(string severity, string debt, int items = 1) +{ + if (debt == null || severity == null) return 0; + var qSeverity = (QubooSeverity)Enum.Parse(typeof(QubooSeverity), severity); + var iDebt = int.Parse(Regex.Replace(debt, @"[^\d]", "")); + return Score(qSeverity, iDebt, items); +} + +public int Score(QubooSeverity severity, int debt, int items = 1) +{ + //$"Math.Max(1, {debt} / 10 * {(int)severity}) * {items} items".Dump(); + return Math.Max(1, debt / 10 * (int)severity) * items; +} + +void ReportIssues(IEnumerable issues) +{ + var byTeam = issues + .OrderBy(i => GetUserGroup(i.assignee ?? i.author ?? "")) + .ThenBy(i => i.component) + .ThenBy(i => i.type) + .ThenBy(i => i.severity) + .Select(i => new + { + assignee = GetUserGroup(i.assignee ?? i.author ?? "Not assigned"), + i.component, + i.message, + i.type, + i.status, + i.severity, + i.effort, + i.creationDate, + i.closeDate, + lineNumber = i.line, + i.taglist + }) + .GroupBy(i => i.assignee, (g, d) => new TeamGrouper( + g, + d.GroupBy(dd => new { type = Path.GetExtension(dd.component), dd.component }, (gg, gd) => + new ComponentGrouper( + gg.type, + gg.component, + gd.GroupBy(yy => new + { + yy.creationDate.Year, + yy.creationDate.Month, + yy.type, + yy.status, + yy.severity + }, (gdk, gdd) => + new SummaryGrouper( + gdk.Year, + gdk.Month, + gdk.status, + gdk.type, + gdk.severity, + gdd.Count() + )).OrderByDescending(yy => yy.Year) + .ThenByDescending(yy => yy.Month) + )) + .GroupBy(dd => dd.Solution, (xg, xd) => new SolutionGrouper + ( + xg, + xd.GroupBy(y => y.Project, (yg, yd) => new ProjectGrouper + ( + yg, + yd.OrderBy(x => x.Path).ThenBy(x => x.FileName) + )).OrderBy(x => x.Project) + )) + .OrderBy(dd => dd.Solution) + )) + .OrderBy(i => i.Team).ToList(); + byTeam.ForEach(team => + { + team.Solutions.ForEach(solution => + { + solution.Solution.Dump().DumpX(team.Team); ; + solution.Projects.Dump(10).DumpX(team.Team); + }); + }); +} + +#region User Group Definition + +public void PopulateUserGroups() +{ + GroupUsers.Add("Architecture", new List { }); + GroupUsers.Add("The A-Team", new List { "tlamb", "tdebolt" }); + GroupUsers.Add("Ryan King", new List { "rreimer", "jpollard", "chelm", "aschey" }); + GroupUsers.Add("Cube Killers", new List { "yrhee", "dforero", "lbehmer" }); + GroupUsers.Add("Kobra Kaizer", new List { "mschmidt", "nbuckle", "fsweis", "jmorales" }); + GroupUsers.Add("Team Sloth", new List { "myoung", "bkrehl", "nnawale", "lrenadesouza", "nleroy" }); + GroupUsers.Add("Team Thanos", new List { "bwells", "zbruin", "zhare", "mwynne", "mdeboer", "jnarofsky" }); + GroupUsers.Add("Platform", new List { "mleitch", "awolek", "jrapp", "cbello", "jchau", "hgutta", "ljian" }); + GroupUsers.Add("Boo", new List { "kferchuk", "akuten", "hvladyka", "vfay" }); + GroupUsers.Add("Jedi", new List { "akost", "sdominska", "tparashchak", "opalamar" }); + GroupUsers.Add("Pokemon", new List { "okrainyk", "mstepanov", "yantoniuk" }); + GroupUsers.Add("Tropic Thunder", new List { "ainzhyievskyi", "ihalenok", "dpanteliuk", "akorchynskyi" }); + GroupUsers.Add("Bee Swarmers", new List { "tscanlan", "cburke", "sxie" }); + GroupUsers.Add("The Moustache", new List { "wrusinko" }); +} + +public string GetUserGroup(string user) +{ + var group = GroupUsers.Where(gu => gu.Value.Contains(user)).FirstOrDefault(); + return group.Key ?? $"unknown {user}"; +} + +#endregion + +#region Issues Report + +public class SolutionGrouper +{ + public string Solution { get; set; } + public List Projects { get; set; } + + public SolutionGrouper(string solution, IOrderedEnumerable projects) + { + Solution = solution; + Projects = projects.ToList(); + } +} + +public class ProjectGrouper +{ + public string Project { get; set; } + public IOrderedEnumerable Issues { get; set; } + + public ProjectGrouper(string project, IOrderedEnumerable issues) + { + Project = project; + Issues = issues; + } +} + +public class TeamGrouper +{ + public string Team { get; set; } + public List Solutions { get; set; } + + public TeamGrouper(string team, IOrderedEnumerable solutions) + { + Team = team; + Solutions = solutions.ToList(); + } +} + +public class ComponentGrouper +{ + public string Solution { get; set; } + public List Issues { get; set; } + public string Component { get; set; } + public string Path { get; set; } + public string Project { get; set; } + public string FileName { get; set; } + public string Extension { get; set; } + public string Url { get; set; } + + public ComponentGrouper() + { + + } + + public ComponentGrouper(string type, string component, IOrderedEnumerable issues) + { + Component = component.Split(new[] { ':' }).Last().Replace('/', '\\'); + Solution = component.Split(new[] { ':' }).First(); + Extension = type.TrimStart(new[] { '.' }); + var filePath = $@"D:\{Component}"; + Path = System.IO.Path.GetDirectoryName(filePath); + var pathParts = Path.Split(System.IO.Path.DirectorySeparatorChar); + //pathParts.Dump(); + if (new[] { "Code", "Internal Tools", "src" }.Contains(pathParts[1])) + { + Project = pathParts.Skip(2).First(); + Path = string.Join($"{System.IO.Path.DirectorySeparatorChar}", pathParts.Skip(2)); + } + else + { + Project = pathParts.Skip(1).First(); + Path = string.Join($"{System.IO.Path.DirectorySeparatorChar}", pathParts.Skip(1)); + } + FileName = System.IO.Path.GetFileName(filePath); + Issues = issues.ToList(); + Url = HttpUtility.HtmlEncode($@"{component}"); + } + object ToDump() => new + { + Issues, + Path, + FileName = new Hyperlinq($@"https://sonarqube.sdt.local/code?id={Url}", FileName) + }; +} + +public class SummaryGrouper +{ + public int Year { get; set; } + public int Month { get; set; } + public string Status { get; set; } + public string Type { get; set; } + public string Severity { get; set; } + public int Items { get; set; } + + public SummaryGrouper() + { + + } + public SummaryGrouper(int year, int month, string status, string type, string severity, int count) + { + Year = year; + Month = month; + Status = status; + Type = type; + Severity = severity; + Items = count; + } + + object ToDump() => new + { + Date = $"{(new DateTime(Year, Month, 1)):yyyy/MM}", + Status, + Type, + Severity, + Count = $"{Items}" + }; +} + +#endregion + +public void WriteReport(List issues) +{ + var reports = issues + .GroupBy(sdm => new + { + author = sdm.author ?? sdm.assignee ?? "", + project = sdm.project, + componentKey = sdm.componentKey, + status = sdm.status ?? "", + severity = sdm.severity ?? "", + resolution = sdm.resolution ?? "", + type = sdm.type, + rule = sdm.rule + }, (g, d) => new IssueReport + { + group = new IssueGroup + { + author = g.author, + project = g.project, + componentKey = g.componentKey, + status = g.status, + severity = g.severity, + resolution = g.resolution, + type = g.type, + rule = g.rule, + issues = d.Count() + }, + issues = d.Select(issue => (IssueReportIssue)issue).ToList() + }) + .OrderBy(r => r.group.author) + .ThenBy(r => r.group.project) + .ToList(); + reports.ForEach(report => + { + //"".PadLeft(40, '―').Dump(); + // report.group.Dump(); + var issueList = report.issues + .GroupBy(i => new { i.message, i.debt, i.effort, i.fileType, i.assignee, i.comment }, (g, d) => new + { + g.message, + debt = g.debt * d.Count(), + effort = g.effort * d.Count(), + g.fileType, + g.assignee, + g.comment, + createdAt = $"{d.Min(i => i.createdAt):d}", + closedAt = $"{d.Max(i => i.closedAt):d}", + daysToClose = (int)d.Max(i => i.closedAt).Subtract(d.Min(i => i.createdAt)).TotalDays, + occurred = d.Count() + }); + new + { + report.group, + issueList + }.Dump(); + // if (issueList.Count() > 1000) + // { + // issueList + // .Select((issue, index) => new { issue, index }) + // .GroupBy(x => x.index / 1000, (key, y) => y.Select(z => z.issue)) + // .Dump(); + // } + // else + // { + // issueList.Dump(); + // } + }); +} + +public void SummarizeIssues(RestClient client) +{ + var types = new[] { "VULNERABILITY", "BUG", "CODE_SMELL" }; + var severities = new[] { "BLOCKER", "CRITICAL", "MAJOR" }; + var issues = GetIssues(client); + var CiStarterSet = issues + .Where(i => i.status != "CLOSED" + && new[] { "BLOCKER", "CRITICAL", "MAJOR" }.Contains(i.severity) + ); + CiStarterSet + .OrderBy(i => i.rule == "csharpsquid:S3776" ? 99 + : i.severity == "MAJOR" ? 2 + : i.severity == "BLOCKER" ? 0 + : i.severity == "CRITICAL" ? 1 : 99) + .GroupBy(i => i.component +, (g, d) => new +{ + key = g, + critical = d.Count(x => x.severity == "CRITICAL"), + ageInYears = (int)(d.Min(x => DateTime.Now.Subtract(x.creationDate).TotalDays) / 365), + team = "" +}) + .OrderByDescending(i => i.ageInYears) + .ThenBy(i => i.critical) + .ThenBy(i => i.key) + //.ThenBy(i => i.key) + .Dump(); +} + +JObject GetVersion(RestClient client) +{ + return GetJson(client, "/api/server/system"); +} + +#region Rule Management + +List GetRules(RestClient client) +{ + List rules = new List(); + var pageNo = 1; + while (true) + { + var info = ListRules(client, pageNo); + if (info == null) break; + var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(info)).rules; + if (deserialized == null || !deserialized.Any()) break; + pageNo += 1; + var page = deserialized; //.Where(i => i.rule.StartsWith("csharpsquid:")); + if (!page.Any()) continue; + rules.AddRange(page); + } + return rules; +} + +JObject ListRules(RestClient client, int page = 1, int pageSize = 500) +{ + return GetJson(client, "/api/rules/search", new List { + new Parameter("ps", pageSize, ParameterType.QueryString), + new Parameter("p", page, ParameterType.QueryString) + }); +} + +public class Rule +{ + public string key { get; set; } + public string repo { get; set; } + public string name { get; set; } + public DateTime createdAt { get; set; } + public string htmlDesc { get; set; } + public string mdDesc { get; set; } + public string severity { get; set; } + public bool isBlockerIssue => severity == "BLOCKER"; + public bool isCriticalIssue => severity == "CRITICAL"; + public bool isMajorIssue => severity == "MAJOR"; + public string status { get; set; } + public string internalKey { get; set; } + public bool isTemplate { get; set; } + public List tags { get; set; } + public List sysTags { get; set; } + public string lang { get; set; } + public string langName { get; set; } + public List @params { get; set; } + public string defaultDebtRemFnType { get; set; } + public string defaultDebtRemFnCoeff { get; set; } + public bool debtOverloaded { get; set; } + public string debtRemFnType { get; set; } + public string debtRemFnCoeff { get; set; } + public string defaultRemFnType { get; set; } + public string defaultRemFnGapMultiplier { get; set; } + public string remFnType { get; set; } + public string remFnGapMultiplier { get; set; } + public bool remFnOverloaded { get; set; } + public string scope { get; set; } + public bool isExternal { get; set; } + public string type { get; set; } + public bool isVulnerability => type == "VULNERABILITY"; + public bool isBug => type == "BUG"; + public bool isCodeSmell => type == "CODE_SMELL"; +} + +#endregion + +#region User Management + +JObject ListUsers(RestClient client) +{ + return GetJson(client, "/api/users/search"); +} + +public void AddNewUsers(RestClient client) +{ + var names = @"User Name Email First Name Last Name +sdt\ainzhyievskyi ainzhyievskyi@stratadecision.com Artur Inzhyievskyi +sdt\dpanteliuk dpanteliuk@stratadecision.com Dmytro Panteliuk +sdt\vivanov vivanov@stratadecision.com Vadym Ivanov +sdt\akorchynskyi akorchynskyi@stratadecision.com Andrii Korchynskyi +sdt\akost aksot@stratadecision.com Andrii Kost +sdt\tparashchak tparashchak@stratadecision.com Taras Parashchak +sdt\sdominska sdominska@stratadecision.com Svitlana Dominska +sdt\opalamar opalamar@stratadecision.com Oleksii Palamar +sdt\vfay vfay@stratadecision.com Vasyl Fay +sdt\kferchuk kferchuk@stratadecision.com Kostyantyn Ferchuk +sdt\hvladyka hvladyka@stratadecision.com Halyna Vladyka +sdt\ihalenok ihalenok@stratadecision.com Iryna Halenok +sdt\akuten akuten@stratadecision.com Andrii Kuten +sdt\yantoniuk yantoniuk@stratadecision.com Yurii Antoniuk +sdt\mstepanov mstepanov@stratadecision.com Mykhailo Stepanov" + .Replace("\r\n", "\r").Split('\r').Skip(1) + .Select(x => x.Split('\t')).ToList() + .ConvertAll(x => new NewUser + { + name = $"{x[2]} {x[3]}", + login = x[0].Replace(@"sdt\", ""), + password = "Password1", + email = x[1] + }); + var users = ListUsers(client); + var logins = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(users)).users; + names.Where(n => !logins.Select(l => l.login).Contains(n.login)).Dump(); + names.Where(n => !logins.Select(l => l.login).Contains(n.login)).ToList() + .ForEach(n => CreateUser(client, n)); +} + +void CreateUser(RestClient client, NewUser user) +{ + client.BaseUrl = new Uri(BaseUrl); + client.Authenticator = new HttpBasicAuthenticator("admin", "admin"); + var request = new RestRequest(); + request.Resource = "/api/users/create"; + request.Method = Method.POST; + request.RequestFormat = DataFormat.Json; + request.AddParameter(new Parameter("login", user.login, ParameterType.QueryString)); + request.AddParameter(new Parameter("password", user.password, ParameterType.QueryString)); + request.AddParameter(new Parameter("password_confirmation", user.password, ParameterType.QueryString)); + request.AddParameter(new Parameter("name", user.name, ParameterType.QueryString)); + request.AddParameter(new Parameter("email", user.email, ParameterType.QueryString)); + request.Dump(); + var response = client.Execute(request); + response.Dump(); + +} + +public class User +{ + public string login { get; set; } + public string name { get; set; } +} + +public class NewUser : User +{ + public string email { get; set; } + public string password { get; set; } +} + +#endregion + +#region Web Services + +public void DumpWebServices(RestClient client) +{ + var services = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(ListWebServices(client))).webServices; + services.Dump(); +} + +JObject ListWebServices(RestClient client) +{ + return GetJson(client, "/api/webservices/list"); +} + +#endregion + +#region Issue Management + +List GetIssues(RestClient client, List parameters = null) +{ + List issues = new List(); + var pageNo = 1; + while (true) + { + var info = ListIssues(client, pageNo, parameters); + if (info == null) break; + pageNo += 1; + var root = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(info)); + if (root.errors?.Any() ?? false) + { + root.errors.Dump(); + break; + } + var deserialized = root.issues; + if (deserialized == null || !deserialized.Any()) break; + issues.AddRange(deserialized); + } + return issues; +} + +JObject ListIssues(RestClient client, int page = 1, List parameters = null, int pageSize = 500) +{ + var queryParameters = new List { + new Parameter("ps", pageSize, ParameterType.QueryString), + new Parameter("p", page, ParameterType.QueryString), + new Parameter("additionalFields", "comments", ParameterType.QueryString) + }; + if (parameters?.Any() ?? false) + queryParameters.RemoveAll(qp => parameters.Select(p => p.Name).Contains(qp.Name)); + if (parameters != null) + queryParameters.AddRange(parameters); + return GetJson(client, "/api/issues/search", queryParameters); +} + +#endregion + +#region Project Management + +//List GetProjects(RestClient client, List parameters = null) +//{ +// List issues = new List(); +// var pageNo = 1; +// while (true) +// { +// var info = ListProjects(client, pageNo, parameters); +// if (info == null) break; +// pageNo += 1; +// var root = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(info)); +// if (root.errors?.Any() ?? false) +// { +// root.errors.Dump(); +// break; +// } +// var deserialized = root.issues; +// if (deserialized == null || !deserialized.Any()) break; +// issues.AddRange(deserialized); +// } +// return issues; +//} + +JObject ListProjects(RestClient client, int page = 1, List parameters = null, int pageSize = 500) +{ + var queryParameters = new List { + new Parameter("ps", pageSize, ParameterType.QueryString), + new Parameter("p", page, ParameterType.QueryString) + }; + if (parameters?.Any() ?? false) + queryParameters.RemoveAll(qp => parameters.Select(p => p.Name).Contains(qp.Name)); + if (parameters != null) + queryParameters.AddRange(parameters); + return GetJson(client, "/api/projects/search", queryParameters); +} + +#endregion + +#region Data Classes + +public class IssueComment +{ + public string key { get; set; } + public string login { get; set; } + public string htmlText { get; set; } + public string markdown { get; set; } + public bool updatable { get; set; } + public DateTime createdAt { get; set; } +} + +public class IssueGroup +{ + public string project { get; set; } + public string componentKey { get; set; } + public string author { get; set; } + public string severity { get; set; } + public string status { get; set; } + public string type { get; set; } + public string resolution { get; set; } + public string rule { get; set; } + public int issues { get; set; } + public object ToDump() => new[] { this }; +} + +public class Issue +{ + public string severity { get; set; } + public SonarSeverity severityId => (SonarSeverity)Enum.Parse(typeof(SonarSeverity), severity); + public bool isBlocker => severityId == SonarSeverity.BLOCKER; + public bool isCritical => severityId == SonarSeverity.CRITICAL; + public bool isMajor => severityId == SonarSeverity.MAJOR; + public bool isMinor => severityId == SonarSeverity.MINOR; + public bool isInfo => severityId == SonarSeverity.INFO; + public string status { get; set; } + public SonarStatus statusId => (SonarStatus)Enum.Parse(typeof(SonarStatus), status); + public bool isOpen => statusId == SonarStatus.OPEN; + public bool isClosed => statusId == SonarStatus.CLOSED; + public bool isReviewed => statusId == SonarStatus.REVIEWED; + public bool isResolved => statusId == SonarStatus.RESOLVED; + public bool isInReview => statusId == SonarStatus.TO_REVIEW; + public string type { get; set; } + public SonarType typeId => (SonarType)Enum.Parse(typeof(SonarType), type); + public bool isVulnerability => typeId == SonarType.VULNERABILITY; + public bool isSecurityHotspot => typeId == SonarType.SECURITY_HOTSPOT; + public bool isBug => typeId == SonarType.BUG; + public bool isCodeSmell => typeId == SonarType.CODE_SMELL; + public string resolution { get; set; } + public SonarResolution resolutionId => (SonarResolution)Enum.Parse(typeof(SonarResolution), resolution); + public bool wontfix => resolutionId == SonarResolution.WONTFIX; + public List comments { get; set; } + public string message { get; set; } + public string key { get; set; } + public string rule { get; set; } + public string debt { get; set; } + public string project { get; set; } + public string component { get; set; } + internal string[] componentParts => component.Split('/'); + public string componentKey => componentParts.Count() > 3 && componentParts[1] == "Strata.Jazz.Web" && componentParts[2] == "Areas" + ? Regex.Replace(componentParts[3], "^Strata.", "") + : componentParts.Count() > 3 && componentParts[1] == "Strata.Jazz.Web" && componentParts[2] != "Areas" + ? Regex.Replace(componentParts[2], "^Strata.", "") + : componentParts.Count() > 1 + ? Regex.Replace(componentParts[1], "^Strata.", "") + : component; + public string fileType => component.Substring(component.LastIndexOf('.') + 1); + public int line { get; set; } + public TextRange textRange { get; set; } + public List flows { get; set; } + public string effort { get; set; } + public string assignee { get; set; } + public string author { get; set; } + // public string hash { get; set; } + public List tags { get; set; } + public string taglist => string.Join(", ", tags); + public DateTime creationDate { get; set; } + public int ageInYears => (int)DateTime.Now.Subtract(creationDate).TotalDays / 365; + public DateTime updateDate { get; set; } + // public string organization { get; set; } + public bool fromHotspot { get; set; } + public DateTime? closeDate { get; set; } + // public string __invalid_name__effort { get; set; } + + public static explicit operator UserQuery.IssueReportIssue(Issue issue) + { + var debt = issue.debt ?? "0"; + var effort = issue.effort ?? "0"; + var r1 = new Regex(@"[^\d]*"); + var r2 = new Regex(@"[\d]*"); + var debtInterval = 1; + switch (r2.Replace(debt, "")) + { + case "min": debtInterval = 1; break; + case "day": debtInterval = 60 * 24; break; + default: debtInterval = Int32.MaxValue; break; + } + var effortInterval = 1; + switch (r2.Replace(effort, "")) + { + case "min": effortInterval = 1; break; + case "day": effortInterval = 60 * 24; break; + default: effortInterval = Int32.MaxValue; break; + } + var i = new UserQuery.IssueReportIssue + { + message = issue.message, + debt = Convert.ToInt32(r1.Replace(debt, "")) * debtInterval, + effort = Convert.ToInt32(r1.Replace(effort, "")) * effortInterval, + fileType = issue.fileType, + assignee = issue.comments.FirstOrDefault()?.login ?? "", + comment = issue.comments.FirstOrDefault()?.markdown ?? "", + createdAt = issue.creationDate, + closedAt = issue.comments.FirstOrDefault()?.createdAt ?? issue.closeDate ?? DateTime.Now + }; + return i; + } + +} + +public class IssueReportGroup +{ + public string message { get; set; } + public int debt { get; set; } + public int effort { get; set; } + public string fileType { get; set; } + public string assignee { get; set; } + public string comment { get; set; } +} + +public class IssueReportIssue : IssueReportGroup +{ + public DateTime createdAt { get; set; } + public DateTime closedAt { get; set; } + public int daysToClose { get; set; } + public int occurred { get; set; } +} + +public class IssueReport +{ + public IssueGroup group; + public List issues; +} + +#endregion + +void Other(RestClient client) +{ + var issues = GetJson(client, "/api/issues/search?assignees=tlamb&severities=BLOCKER,CRITICAL"); + JsonConvert.DeserializeObject(JsonConvert.SerializeObject(issues)).issues + .GroupBy(i => new + { + i.rule, + i.project, + i.type + }, (g, d) => new + { + issue = new + { + type = g.type, + id = g.rule, + project = g.project, + severity = d.First().severity, + message = d.First().message, + issues = d.Count() + }, + issues = d.Select(i => new + { + i.status, + i.component, + i.line, + i.message, + i.textRange, + i.effort, + i.debt, + i.key + }) + }) + .Dump(); +} + +// Define other methods and classes here + +#region RestSharp Helpers + +JObject GetJson(RestClient client, string something, List parameters = null) +{ + client.BaseUrl = new Uri(BaseUrl); + RestRequest request = new RestRequest(); + request.Resource = something; + request.Method = Method.GET; + if (parameters?.Any() ?? false) + request.Parameters.AddRange(parameters); + return JObject.Parse(client.Execute(request).Content); +} + +dynamic GetList(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var converter = new ExpandoObjectConverter(); + return JsonConvert.DeserializeObject(client.Execute(request).Content, converter); +} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content, + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Error.Message.Dump(); + args.ErrorContext.Handled = true; + } + }); +} + +#endregion + +#region json2csharp + +public class Paging +{ + public int pageIndex { get; set; } + public int pageSize { get; set; } + public int total { get; set; } +} + +public class TextRange +{ + public int startLine { get; set; } + public int endLine { get; set; } + public int startOffset { get; set; } + public int endOffset { get; set; } + + object ToDump() => startLine != endLine + ? $"L{startLine}:{endLine},O{startOffset}:{endOffset}" + : $"L{startLine},O{startOffset}:{endOffset}"; +} + +public class FlowComponent +{ + public string component { get; set; } + public TextRange textRange { get; set; } + public string msg { get; set; } +} + +public class Flow +{ + public List locations { get; set; } +} + +public class SonarError +{ + public string msg { get; set; } +} + +public class Component +{ + public string organization { get; set; } + public string key { get; set; } + public string uuid { get; set; } + public bool enabled { get; set; } + public string qualifier { get; set; } + public string name { get; set; } + public string longName { get; set; } + public string path { get; set; } +} + +public class RootObject +{ + public int total { get; set; } + public int p { get; set; } + public int ps { get; set; } + public UserQuery.Paging paging { get; set; } + public int effortTotal { get; set; } + public int debtTotal { get; set; } + // public int majorIssues => issues.Count(i => i.severity == "MAJOR"); + // public int criticalIssues => issues.Count(i => i.severity == "CRITICAL"); + public int vulnerabilityIssues => issues.Count(i => i.type == "VULNERABILITY"); + public int bugIssues => issues.Count(i => i.type == "BUG"); + public int codeSmells => issues.Count(i => i.type == "CODE_SMELL"); + public List errors { get; set; } + public List issues { get; set; } + public List components { get; set; } + public List facets { get; set; } + public List rules { get; set; } + public List users { get; set; } +} + +#endregion + +#region WebServices + +public class WSActionParam +{ + public string key { get; set; } + public string description { get; set; } + public bool required { get; set; } + public bool @internal { get; set; } + public object exampleValue { get; set; } + public string defaultValue { get; set; } + public List possibleValues { get; set; } + public string deprecatedKey { get; set; } + public string deprecatedKeySince { get; set; } + public int? maximumValue { get; set; } + public string since { get; set; } + public string deprecatedSince { get; set; } + public int? minimumLength { get; set; } + public int? maxValuesAllowed { get; set; } + public int? maximumLength { get; set; } +} + +public class WSAction +{ + public string key { get; set; } + public string description { get; set; } + public string since { get; set; } + public bool @internal { get; set; } + public bool post { get; set; } + public bool hasResponseExample { get; set; } + public List changlog { get; set; } + public List Params { get; set; } + public string deprecatedSince { get; set; } +} + +public class WebService +{ + public string path { get; set; } + public string description { get; set; } + public List actions { get; set; } + public string since { get; set; } +} + +public class WebServices +{ + public List webServices { get; set; } +} + +#endregion \ No newline at end of file diff --git a/SonarQube API/Test the math.linq b/SonarQube API/Test the math.linq new file mode 100644 index 0000000..7bdb10c --- /dev/null +++ b/SonarQube API/Test the math.linq @@ -0,0 +1,30 @@ + + +public enum Severity +{ + Info = 1, + Minor = 2, + Major = 5, + Critical = 7, + Blocker = 10 +} + +void Main() +{ + Score(Severity.Critical, 5, 18).Dump(); + ScoreAlt(Severity.Critical, 5, 18).Dump(); +} + +// Define other methods and classes here + +public int Score(Severity severity, int debt, int items = 1) +{ + $"Math.Max(1, {debt} / 10 * {(int)severity}) * {items} items".Dump(); + return Math.Max(1, debt / 10 * (int)severity) * items; +} + +public int ScoreAlt(Severity severity, int debt, int items = 1) +{ + $"Math.Max(1, {debt} * {(int)severity} / 10) * {items} items".Dump(); + return Math.Max(1, debt * (int)severity / 10) * items; +} diff --git a/Split text by a phrase.linq b/Split text by a phrase.linq new file mode 100644 index 0000000..97a04c1 --- /dev/null +++ b/Split text by a phrase.linq @@ -0,0 +1,77 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var text = @"SELECT * +FROM cci.RunSavingHistory AS rsh +ORDER BY rsh.DateCreated DESC +GO +DELETE FROM cci.RunSavingHistory +"; + +var temp = System.IO.Path.GetTempFileName(); +File.WriteAllText(temp, text); +var input = File.ReadAllLines(temp); +var grp = 0; +input.Select(r => +{ + if (r.Equals("go", StringComparison.CurrentCultureIgnoreCase)) + { + r = ""; + return new {grp = grp++, r}; + } + else + { + return new {grp, r}; + } +}).GroupBy(r => r.grp, (x, lines) => string.Join(" ", lines.Select(l => l.r).Where(l => !string.IsNullOrEmpty(l)))).Dump(); diff --git a/StarterSet API/Standard Definition Mapping Standards.linq b/StarterSet API/Standard Definition Mapping Standards.linq new file mode 100644 index 0000000..5d9ec4f --- /dev/null +++ b/StarterSet API/Standard Definition Mapping Standards.linq @@ -0,0 +1,23 @@ + + + db640701-a1c5-4177-9f03-5152d093ffa7 + true + D0011-sql-01.sdt.local + jazz tst StrataSphere 20200612.1 + true + + Newtonsoft.Json + Newtonsoft.Json.Linq + + +var definitions = (from sdm in StandardDefinitionMappings select sdm).ToList(); +//definitions +//.OrderBy(d => d.StandardDefinitionType) +//.ThenBy(d => $"{JObject.Parse(d.MappingMemberValue)["mappings"][0]["text"]}") +//.Select(x => new { x.StandardDefinitionGUID, x.StandardDefinitionType, x.MappingMemberValue }).Dump(nameof(definitions)); +var inserts = definitions +.OrderBy(d => d.StandardDefinitionType) +.ThenBy(d => $"{JObject.Parse(d.MappingMemberValue)["mappings"][0]["text"]}") +.Aggregate("INSERT INTO dbo.StandardDefinitionMapping ( StandardDefinitionGUID, StandardDefinitionType, MappingMemberValue )\r\nVALUES", + (x, y) => $"{x}\r\n\t('{y.StandardDefinitionGUID}', N'{y.StandardDefinitionType}', N'{y.MappingMemberValue}'),"); +inserts.TrimEnd(',').Dump(nameof(inserts)); diff --git a/StarterSet API/Starter Set API Definitions Search.linq b/StarterSet API/Starter Set API Definitions Search.linq new file mode 100644 index 0000000..b887ca5 --- /dev/null +++ b/StarterSet API/Starter Set API Definitions Search.linq @@ -0,0 +1,318 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + jazz tst Riverside Health System 20190930.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + + +private string BaseUrl = "https://api-dev.sdt.local/StrataSphere.Web.API.Service/api/v1/"; +private IList _mappedDefinitions; + +void Main() +{ + RestClient client = new RestClient(); + var definitions = GetList(client, "Definitions"); + var standardDefinitionMappings = from def in StandardDefinitionMappings + select new + { + def.MappingId, + def.StandardDefinitionGUID, + def.StandardDefinitionType, + MappingMemberValue = JsonConvert.DeserializeObject(def.MappingMemberValue) + }; + var guidDefinitionDictionary = standardDefinitionMappings.ToDictionary(u => u.StandardDefinitionGUID); + var foundDefinitions = definitions.Where(p => guidDefinitionDictionary.ContainsKey(p.Id)); + _mappedDefinitions = (from d in foundDefinitions + join m in StandardDefinitionMappings on d.Id equals m.StandardDefinitionGUID + select new StrataSphereMappedDefinition(d, m.MappingMemberValue)).ToList(); + + var pathAlias = "HIERALIAS"; + var sqlTableAlias = "viewDimMetri"; + var attributeID = new[] { "Cardiomyopathy" }.ToList(); + StrataSphereMappedValue find; + attributeID.ForEach(id => + { + find = MapToStrataSphere("[Case Type Family MSDRG]", "[Case Type Family MSDRG].[Case Type Family]", + new List { $"{id}" }); + find.Dump($"StrataSphereMappedValue: {id}"); + }); +} + +// Define other methods and classes here +public StrataSphereMappedValue MapToStrataSphere(string dimensionId, string attributeId, IList valuesToMap) +{ + var mdx = new Regex(@"^(\[.+\]\.)+\[.+\]$"); + var clientValues = valuesToMap.Select(valueToMap => mdx.IsMatch(valueToMap) + ? AnalysisServicesUtils.GetMeasureIDFromMDXName(valueToMap) + : valueToMap).ToList(); + return FindMappedValue(dimensionId, attributeId, clientValues); +} + +public static class AnalysisServicesUtils +{ + public static string GetMeasureIDFromMDXName(string aMemberMDXName) + { + return aMemberMDXName; + } +} + +protected StrataSphereMappedValue FindMappedValue(string dimensionId, string attributeId, List valuesToMap) +{ + var definitions = _mappedDefinitions + .Where(d => d.DimensionId.Equals(dimensionId, StringComparison.CurrentCultureIgnoreCase) + && d.AttributeId.Equals(attributeId, StringComparison.CurrentCultureIgnoreCase)).ToList(); + var mappings = definitions.Where(p => p.MappedValues != null && p.MappedValues.mappings.Any()).SelectMany(p => p.MappedValues.mappings); + mappings.Dump(); + var mappedDefinition = definitions + .SingleOrDefault(p => p.MappedValues != null + && (!p.MappedValues.mappings.Any() || + p.MappedValues.mappings.SelectMany(m => m.attributeValues + .Select(a => a.ToString())) + .OrderBy(v => v).SequenceEqual(valuesToMap.OrderBy(v => v), StringComparer.CurrentCultureIgnoreCase))) ?? + definitions + .SingleOrDefault(p => p.MappedValues != null + && (!p.MappedValues.mappings.Any() || + p.MappedValues.mappings + .Select(m => m.name) + .OrderBy(v => v).SequenceEqual(valuesToMap.OrderBy(v => v), StringComparer.CurrentCultureIgnoreCase))) ?? + definitions + .SingleOrDefault(p => p.MappedValues != null + && (!p.MappedValues.mappings.Any() || + p.MappedValues.mappings + .Select(m => m.text) + .OrderBy(v => v).SequenceEqual(valuesToMap.OrderBy(v => v), StringComparer.CurrentCultureIgnoreCase))) ?? + definitions + .SingleOrDefault(p => p.MappedValues != null + && (!p.MappedValues.mappings.Any() || + p.MappedValues.mappings + .Select(m => m.id) + .OrderBy(v => v).SequenceEqual(valuesToMap.OrderBy(v => v), StringComparer.CurrentCultureIgnoreCase))) ?? + definitions + .SingleOrDefault(p => p.MappedValues != null + && (!p.MappedValues.mappings.Any() || + p.MappedValues.mappings + .SelectMany(m => m.hierarchyPaths) + .OrderBy(v => v).SequenceEqual(valuesToMap.OrderBy(v => v), StringComparer.CurrentCultureIgnoreCase))) ?? + definitions.FirstOrDefault(); + + return mappedDefinition != null + ? new StrataSphereMappedValue(valuesToMap, mappedDefinition.StrataSphereDefinitionGuid) + : new StrataSphereMappedValue(valuesToMap); +} + +public struct StrataSphereMappedValue +{ + public IList ClientValues { get; set; } + + public Guid? StrataSphereDefinitionGuid { get; set; } + + public StrataSphereMappedValue(IList clientValues) + { + ClientValues = clientValues; + StrataSphereDefinitionGuid = null; + } + + public StrataSphereMappedValue(IList clientValues, Guid definitionGuid) + { + ClientValues = clientValues; + StrataSphereDefinitionGuid = definitionGuid; + } + + public bool IsMapped => StrataSphereDefinitionGuid.HasValue; +} + +public class StrataSphereMappedDefinition +{ + public StrataSphereMappedDefinition(DefinitionDto definitionDto, string mappedValues) + { + StrataSphereDefinitionGuid = definitionDto.Id; + HierarchyGuid = definitionDto.HierarchyGuid; + DimensionGuid = definitionDto.DimensionGuid; + AttributeGuid = definitionDto.AttributeGuid; + HierarchyId = definitionDto.HierarchyId; + DimensionId = definitionDto.DimensionId; + AttributeId = definitionDto.AttributeId; + MappedValues = JsonConvert.DeserializeObject(mappedValues); + } + + public Guid StrataSphereDefinitionGuid { get; } + public Guid HierarchyGuid { get; } + public Guid DimensionGuid { get; } + public Guid AttributeGuid { get; } + public string HierarchyId { get; } + public string DimensionId { get; } + public string AttributeId { get; } + public StrataSphereMappingValues MappedValues { get; } +} + +public class StrataSphereMappingValues +{ + public string HierarchyGUID { get; set; } + public string DimensionGUID { get; set; } + public List values { get; set; } + public List mappings { get; set; } + public List hierarchyPaths { get; set; } + + public StrataSphereMappingValues() + { + mappings = new List(); + } +} + +public class MappingValue +{ + public string id { get; set; } + public string displayHierarchyName { get; set; } + public string text { get; set; } + public string name { get; set; } + public List attributeValues { get; set; } + public List hierarchyPaths { get; set; } + + public MappingValue() + { + attributeValues = new List(); + hierarchyPaths = new List(); + } +} + +public class ApiBaseDto +{ + /// + /// API Item Id Guid in StrataSphere + /// + /// 00000000-0000-0000-0000-000000000000 + public Guid Id { get; set; } + + /// + /// When the API item was uploaded to StrataSphere + /// + public DateTime DateCreated { get; set; } + + /// + /// When the API item was last updated in StrataSphere + /// + public DateTime DateLastModified { get; set; } + +} + +public class DefinitionDto : ApiBaseDto +{ + + /// + /// The name of the definition + /// + /// TOP 10 DRGs BY SERVICE LINE + public string Name { get; set; } + + /// + /// A short description of the definition's content + /// + /// Top 10 DRGs by Service Line filtered per service line rollup + public string Description { get; set; } = ""; + + /// + /// The Guid of the Definition's hierarchy in a GM database + /// + /// 00000000-0000-0000-0000-000000000000 + public Guid HierarchyGuid { get; set; } + + /// + /// The Guid of the Definition's dimension in a GM database + /// + /// 00000000-0000-0000-0000-000000000000 + public Guid DimensionGuid { get; set; } + + /// + /// The Guid of the Definition's attribute in a GM database + /// + /// 00000000-0000-0000-0000-000000000000 + public Guid AttributeGuid { get; set; } + + /// + /// The string of the Definition's hierarchy friendly name + /// + /// PatientTypeRollupID + public string HierarchyId { get; set; } + + /// + /// The string of the Definition's dimension Id + /// + /// [Patient Encounter] + public string DimensionId { get; set; } + + /// + /// The string of the Definition's attribute Id + /// + /// [Patient Encounter].[Service Line Strata Decision] + public string AttributeId { get; set; } + +} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content); +} \ No newline at end of file diff --git a/StarterSet API/Starter Set API Definitions.linq b/StarterSet API/Starter Set API Definitions.linq new file mode 100644 index 0000000..4f59613 --- /dev/null +++ b/StarterSet API/Starter Set API Definitions.linq @@ -0,0 +1,134 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + StrataSphere + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + System.Dynamic + + +private string BaseUrl = "https://api-prod.sdt.local/starterset-api/api/v1/"; //"https://starterset-api.dev.k8s.sdt.local/api/v1/"; + +void Main() +{ + RestClient client = new RestClient(); + client.BaseUrl = new Uri(BaseUrl.Replace("/api/v1/", "/health")); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + client.Execute(request).Content.Dump("health"); + + var definitions = GetList(client, "Definitions"); + definitions? + .OrderBy(d => d.Name).ThenBy(d => d.AttributeId) + .Dump(nameof(definitions)); + var mdx = GetList(client, "MdxScoreToCube"); + mdx? + .OrderBy(d => d.ScoreDimensionName).ThenBy(d => d.CubeDimensionName) + .Dump(nameof(mdx)); +} + +// Define other methods and classes here + +dynamic GetList(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var converter = new ExpandoObjectConverter(); + return JsonConvert.DeserializeObject(client.Execute(request).Content, converter); +} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content, + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Error.Message.Dump(); + args.ErrorContext.Handled = true; + } + }); +} + +public class DefinitionDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public Guid HierarchyGuid { get; set; } + public Guid DimensionGuid { get; set; } + public Guid AttributeGuid { get; set; } + public string HierarchyId { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + + public DefinitionDto() + { + } +} \ No newline at end of file diff --git a/StarterSet API/Starter Set API MdxScoreToCube.linq b/StarterSet API/Starter Set API MdxScoreToCube.linq new file mode 100644 index 0000000..14bf140 --- /dev/null +++ b/StarterSet API/Starter Set API MdxScoreToCube.linq @@ -0,0 +1,138 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + System.Dynamic + + +private string BaseUrl = "https://starterset-api.dev.k8s.sdt.local/api/v1/"; + +void Main() +{ + RestClient client = new RestClient(); + var mdxScoreToCubes = GetList(client, "MdxScoreToCube"); + mdxScoreToCubes + .Where(stc => stc.ScoreDimensionName == "MR Metrics") + //.Where(d => d.DimensionGuid.ToString().Equals("A1823417-0B73-9950-D44C-2F3A9B9DDB92", StringComparison.CurrentCultureIgnoreCase)) + //.OrderBy(d => d.DimensionId) + .Dump(nameof(mdxScoreToCubes)); +} + +// Define other methods and classes here + +dynamic GetList(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var converter = new ExpandoObjectConverter(); + return JsonConvert.DeserializeObject(client.Execute(request).Content, converter); +} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content, + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Error.Message.Dump(); + args.ErrorContext.Handled = true; + } + }); +} + +public class MdxScoreToCubeDto +{ + public Guid Id { get; set; } + public string OrgPin { get; set; } + public Guid DatabaseGuid { get; set; } + public string ScoreDimensionName { get; set; } + public string ScoreHierarchyName { get; set; } + public string CubeDimensionName { get; set; } + public string CubeHierarchyName { get; set; } + public MdxMemberIdTypes MdxMemberIdType {get;set;} + public MdxForamtTypes MdxFormatType {get;set;} + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + + public MdxScoreToCubeDto() + { + } +} + +public enum MdxMemberIdTypes +{ + Attribute, + Name, + Text, + Id, + HierarchyPath +} + +public enum MdxForamtTypes +{ + None, + MDX, + Hierarchy, + MDXMemberId, + Raw +} \ No newline at end of file diff --git a/StarterSet API/Starter Set API Reports.linq b/StarterSet API/Starter Set API Reports.linq new file mode 100644 index 0000000..6fc9788 --- /dev/null +++ b/StarterSet API/Starter Set API Reports.linq @@ -0,0 +1,872 @@ + + + db640701-a1c5-4177-9f03-5152d093ffa7 + true + D0011-sql-01.sdt.local + jazz tst StrataSphere 20191104.1 + true + + Newtonsoft.Json + RestSharp + RestSharp + Newtonsoft.Json.Converters + Newtonsoft.Json + System.Dynamic + + +private string BaseUrl = @"https://localhost:44325/api/v1/"; + +void Main() +{ + RestClient client = new RestClient(); + var reports = GetList(client, "Reports"); + reports.Dump(); +} + +dynamic GetList(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var converter = new ExpandoObjectConverter(); + return JsonConvert.DeserializeObject(client.Execute(request).Content, converter); +} + +void other() +{ + StandardDefinitionMappings.Select(sdm => new + { + sdm.MappingId, + sdm.StandardDefinitionGUID, + sdm.StandardDefinitionType, + MappingMemberValue = JsonConvert.DeserializeObject(sdm.MappingMemberValue) + }).Dump("StandardDefinitionMappings"); + + REReports.Join(REDSCubeReportParameters, + r => r.ReportGUID, + p => p.ReportGUID, + (r, p) => new ReportInfo(p.ParameterXML) + { + Report = r.Name, + DimensionID = p.DimensionID, + AttributeID = p.AttributeID + }).Dump("Cube Reports"); + + REReports.Join(REClientReportParameters, + r => r.ReportGUID, + p => p.ReportGUID, + (r, p) => new ReportInfo(p.ParameterXML) + { + Report = r.Name, + DimensionID = p.DimensionID, + AttributeID = p.AttributeID + }).Dump("Client Reports"); +} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content, + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Error.Message.Dump(); + args.ErrorContext.Handled = true; + } + }); +} + +void stuff(RestClient client) +{ + client.BaseUrl = new Uri(BaseUrl + "Definitions"); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var definitions = JsonConvert.DeserializeObject>(client.Execute(request).Content); + definitions.Where(d => d.DimensionGuid == new Guid("6EF6B1F7-A50C-4198-8866-140BB82E2DDA")).Dump("Definitions"); + + client.BaseUrl = new Uri(BaseUrl + "MDXScoreToCube"); + var mdx = JsonConvert.DeserializeObject>(client.Execute(request).Content); + mdx.Dump("MDX"); + + client.BaseUrl = new Uri(BaseUrl + "Reports"); + var reports = JsonConvert.DeserializeObject>(client.Execute(request).Content); + reports.Dump("Reports"); + + var reportSetupUrl = new Uri(BaseUrl + "Reports/{0}/Setup"); + reports.Where(r => r.Id == new Guid("a4a12e21-954b-4889-d5c8-08d71f2ff590")).ToList().ForEach(r => + { + client.BaseUrl = new Uri(BaseUrl + $"Reports/{r.Id}"); + var rpt = JsonConvert.DeserializeObject(client.Execute(request).Content); + rpt.DefinitionIds.ForEach(d => + { + client.BaseUrl = new Uri(BaseUrl + $"Defintions/{d}"); + var definition = JsonConvert.DeserializeObject>(client.Execute(request).Content); + definition.Dump($"Report {r.Name} Definition {d}"); + }); + }); + +} + +// Define other methods and classes here + +public class ReportInfo +{ + public string Report { get; set; } + public string DimensionID { get; set; } + public string AttributeID { get; set; } + public string ParameterXML { get; set; } + + internal XmlDocument doc; + public string Parameter { get; set; } + public ReportInfo(string parameterXML) + { + ParameterXML = parameterXML; + var parameterXml = ParameterXML = $"{ParameterXML}" + .RemoveAllNamespacesAsString() + .Replace("string>", "valueId>") + .Replace("", "") + .Replace("<_", "<").Replace("( + JsonConvert.SerializeXmlNode(doc.SelectSingleNode("root") + ) + ) + , + Newtonsoft.Json.Formatting.Indented); + } +} + +public class StrataSphereMappingValues +{ + public string HierarchyGUID { get; set; } + public string DimensionGUID { get; set; } + public List values { get; set; } + public List mappings { get; set; } + public List hierarchyPaths { get; set; } + + public StrataSphereMappingValues() + { + mappings = new List(); + } +} + +public class MappingValue +{ + public string id { get; set; } + public string displayHierarchyName { get; set; } + public string text { get; set; } + public string name { get; set; } + public List attributeValues { get; set; } + public List hierarchyPaths { get; set; } + + public MappingValue() + { + attributeValues = new List(); + hierarchyPaths = new List(); + } +} + +public enum eStrataSphereItemCategory +{ + Report, + Dashboard +} + +public enum StrataSphereReportEnum +{ + Report, + DSCubeReport, + SQLReport, + ClientReport +} + +public class ReportDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public eStrataSphereItemCategory Category => eStrataSphereItemCategory.Report; + public string Tagline => + $"Report | {Module} | {DateCreated.ToString("MMM-dd-YYYY")} | {DownloadCount} downloads"; + + public StrataSphereReportEnum ReportType { get; set; } + public string Module { get; set; } + public string MinJazzVersion { get; set; } + public string MaxJazzVersion { get; set; } + public string ReportSetupJson { get; set; } + public List DefinitionIds { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + public int DownloadCount { get; set; } + + public ReportDto() + { + ReportSetupJson = "{}"; + DefinitionIds = new List(); + } +} + +public class DefinitionDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public Guid HierarchyGuid { get; set; } + public Guid DimensionGuid { get; set; } + public Guid AttributeGuid { get; set; } + public string HierarchyId { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } +} + +public enum MDXMemberIDTypeEnum +{ + Attribute, + Name, + Text, + Id, + HierarchyPath +} + +public enum MDXFormatTypeEnum +{ + None, + MDX, + Hierarchy, + MDXMemberId +} + +public class MDXScoreToCubeDto +{ + public string OrgPin { get; set; } + public Guid DatabaseGuid { get; set; } + public string ScoreDimensionName { get; set; } + public string ScoreHierarchyName { get; set; } + public string CubeDimensionName { get; set; } + public string CubeHierarchyName { get; set; } + public MDXMemberIDTypeEnum MDXMemberIDType { get; set; } + public MDXFormatTypeEnum MDXFormatType { get; set; } +} + +public class ValueIDArray +{ + public List valueId { get; set; } +} + +public class DSCubeSearchCondition +{ + public string FilterOp { get; set; } + public string SearchType { get; set; } + public string Value2 { get; set; } + public string Value { get; set; } + public ValueIDArray ValueIDArray { get; set; } +} + +public class SearchConditions +{ + public DSCubeSearchCondition DSCubeSearchCondition { get; set; } +} + +public class DSCubeSearchParameterValue +{ + public string ParameterGUID { get; set; } + public string ParameterValueGUID { get; set; } + public SearchConditions SearchConditions { get; set; } +} + +public class Root +{ + public DSCubeSearchParameterValue DSCubeSearchParameterValue { get; set; } +} + +public class RootObject +{ + public Root root { get; set; } +} + +#region StrataSphereAdHocReportSetup + +public interface IStrataSphereAdHocReportSectionItem +{ + string Name { get; set; } + bool IsOnChartXAxis { get; set; } + bool IsOnChartYAxis { get; set; } +} + +internal class StrataSphereAdHocReportAttribute : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportAttribute() + { + + } + + public string AttributeId { get; set; } + public string DimensionId { get; set; } + public int Index { get; set; } + public string Name { get; set; } + public IList FilterMembers { get; set; } + public int VisibilityStatusValue { get; set; } + public bool ShowSubtotal { get; set; } + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + // section level filters + public List Parameters { get; set; } = new List(); + //public List Parameters { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportCalculation : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportCalculation() + { + } + public string Name { get; set; } + public string CalcType { get; set; } + public int DisplayOrder { get; set; } + public string DisplayFormat { get; set; } + public int ColumnWidth { get; set; } + public string CalculationJson { get; set; } + public string CssClass { get; set; } + public bool IsAttributeMember { get; set; } + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + public List ConditionalFormats { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportConditionalFormat +{ + public StrataSphereAdHocReportConditionalFormat() + { + + } + public string Comment { get; set; } + public int DisplayOrder { get; set; } + public ReportTupleInfo ColumnTupleInfo { get; set; } + public string CssClass { get; set; } + public string ValueToCompareAsString { get; set; } + public int OperatorValue { get; set; } +} + +internal class StrataSphereAdHocReportConfig +{ + public string Title { get; set; } + public string Description { get; set; } + public string[] Colors { get; set; } + public AxisSetting AxisSettings { get; set; } + public string XType { get; set; } + public bool YAxisMultiSelect { get; set; } + public Guid XAxisSectionItemGuid { get; set; } + public List YAxisSectionItemGuids { get; set; } = new List(); + + public StrataSphereAdHocReportConfig(BaseConfig source) + { + if (source == null) return; + Title = source.Title; + Description = source.Description; + Colors = source.Colors; + AxisSettings = source.AxisSettings; + XType = source.XType; + YAxisMultiSelect = source.YAxisMultiSelect; + } + + public BaseConfig GetChartConfig() + { + var chartConfig = default(BaseConfig); + /* + // Try decoding the xType by the name first + var asm = typeof(AreaConfig).Assembly; + var type = asm.GetType($"{asm.GetName().Name}.Reporting.ChartConfigs.{XType}"); + if (type != null) + { + chartConfig = (BaseConfig)Activator.CreateInstance(type); + } + else // if that failed then use the hard coded selector, this is an issue if new types are supported + { + switch (XType) + { + case "AreaConfig": + chartConfig = new AreaConfig(); + break; + case "BarConfig": + chartConfig = new BarConfig(); + break; + case "BubbleConfig": + chartConfig = new BubbleConfig(); + break; + case "ColumnConfig": + chartConfig = new ColumnConfig(); + break; + case "ComboColumnAndLineConfig": + chartConfig = new ComboColumnAndLineConfig(); + break; + case "ComboColumnAndLineWithSecondaryAxisConfig": + chartConfig = new ComboColumnAndLineWithSecondaryAxisConfig(); + break; + case "DonutConfig": + chartConfig = new DonutConfig(); + break; + case "LineConfig": + chartConfig = new LineConfig(); + break; + case "PieConfig": + chartConfig = new PieConfig(); + break; + case "ScatterConfig": + chartConfig = new ScatterConfig(); + break; + case "SplineConfig": + chartConfig = new SplineConfig(); + break; + case "StackedBarConfig": + chartConfig = new StackedBarConfig(); + break; + case "StackedBarPercentConfig": + chartConfig = new StackedBarPercentConfig(); + break; + case "StackedColumnConfig": + chartConfig = new StackedColumnConfig(); + break; + case "StackedColumnPercentConfig": + chartConfig = new StackedColumnPercentConfig(); + break; + } + } + */ + if (chartConfig == null) return chartConfig; + chartConfig.Title = Title; + chartConfig.Description = Description; + chartConfig.Colors = Colors; + chartConfig.AxisSettings = AxisSettings; + // if (chartConfig is XYConfig xyConfig) + // { + // xyConfig.XAxisSectionItemGuid = XAxisSectionItemGuid; + // xyConfig.YAxisSectionItemGuids.AddRange(YAxisSectionItemGuids); + // } + return chartConfig; + } + +} + +internal class StrataSphereAdHocReportDataSource +{ + public StrataSphereAdHocReportDataSource() + { + + } + public Guid DataSourceGuid { get; set; } + public string Name { get; set; } + public int DataSourceType { get; set; } +} + +internal class StrataSphereAdHocReportMeasure : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportMeasure() + { + + } + public string MeasureId { get; set; } + public string Name { get; set; } + public int Index { get; set; } + + public string DisplayFormat { get; set; } + public int ColumnWidth { get; set; } + + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + // section level filters + public List Parameters { get; set; } = new List(); + + public List ConditionalFormats { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportSection +{ + public StrataSphereAdHocReportSection() + { + + } + public string Name { get; set; } + public bool IsOnColumn { get; set; } + public int DisplayOrder { get; set; } + public bool IsTimeRelative { get; set; } + + public bool IsFinancialReportSectionHidable { get; set; } + public bool IsMergingRepeatHeader { get; set; } + public bool IsSpaceAbove { get; set; } + public bool IsHidden { get; set; } + + public string DisplayLabel { get; set; } + public bool ShowSectionLabel { get; set; } + public bool ShowGrandTotal { get; set; } + public bool IsAutoNameFilter { get; set; } + public bool ShowMargin { get; set; } + + public List Attributes { get; set; } = new List(); + + public List Measures { get; set; } = new List(); + + public List Calculations { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportSetup +{ + public string Style { get; set; } + + public StrataSphereAdHocReportSortArgs SortArgs { get; set; } + + public List DataSources { get; set; } = new List(); + + public StrataSphereAdHocReportConfig ChartConfig { get; set; } = null; + + public List Sections { get; set; } = new List(); + + public List Parameters { get; set; } = new List(); + + public List ServiceLines { get; set; } = + new List(); + +} + +public class StrataSphereAdHocReportSortArgs +{ + public StrataSphereAdHocReportTupleInfo TupleInfo { get; set; } + public bool IsAscending { get; set; } + public int SortCount { get; set; } + public int Top { get; set; } + public bool IsTopPercent { get; set; } + public bool IsIncludeAllOthers { get; set; } + + public StrataSphereAdHocReportSortArgs() + { + TupleInfo = new StrataSphereAdHocReportTupleInfo(); + } +} + +public class StrataSphereAdHocReportTupleInfo +{ + public Dictionary PartialRowTuple { get; set; } + public Dictionary PartialColTuple { get; set; } + public string MainMeasureName { get; private set; } + public string RowMeasureName { get; set; } + public string ColMeasureName { get; set; } + public Guid ColMeasureGUID { get; set; } + public string FormatString { get; set; } + public int rowIndex { get; set; } + public int colIndex { get; set; } + public Guid ColumnSectionGUID { get; set; } + public IAdHocReportSectionMeasure MainMeasure { get; set; } + + public StrataSphereAdHocReportTupleInfo() + { + PartialRowTuple = new Dictionary(); + PartialColTuple = new Dictionary(); + ColumnSectionGUID = Guid.Empty; + ColMeasureGUID = Guid.Empty; + } + + public StrataSphereAdHocReportTupleInfo(ReportTupleInfo tupleInfo) + : this() + { + if (tupleInfo == null) return; + tupleInfo.PartialRowTuple.Keys.ToList() + .ForEach(key => PartialRowTuple.Add(key, tupleInfo.PartialRowTuple[key])); + tupleInfo.PartialColTuple.Keys.ToList() + .ForEach(key => PartialColTuple.Add(key, tupleInfo.PartialColTuple[key])); + //MainMeasure = tupleInfo.MainMeasure; + MainMeasureName = tupleInfo.MainMeasureName; + RowMeasureName = tupleInfo.RowMeasureName; + ColMeasureName = tupleInfo.ColMeasureName; + ColMeasureGUID = tupleInfo.ColMeasureGUID; + FormatString = tupleInfo.FormatString; + rowIndex = tupleInfo.rowIndex; + colIndex = tupleInfo.colIndex; + ColumnSectionGUID = tupleInfo.ColumnSectionGUID; + } + + public static implicit operator ReportTupleInfo(StrataSphereAdHocReportTupleInfo tupleInfo) + { + if (tupleInfo == null) return null; + var result = new ReportTupleInfo + { + PartialRowTuple = new Dictionary(), + PartialColTuple = new Dictionary(), + MainMeasure = tupleInfo.MainMeasure?.CopyMeasure(), + RowMeasureName = tupleInfo.RowMeasureName, + ColMeasureName = tupleInfo.ColMeasureName, + ColMeasureGUID = tupleInfo.ColMeasureGUID, + FormatString = tupleInfo.FormatString, + rowIndex = tupleInfo.rowIndex, + colIndex = tupleInfo.colIndex, + ColumnSectionGUID = tupleInfo.ColumnSectionGUID + }; + tupleInfo.PartialRowTuple.Keys.ToList() + .ForEach(key => result.PartialRowTuple.Add(key, tupleInfo.PartialRowTuple[key])); + tupleInfo.PartialColTuple.Keys.ToList() + .ForEach(key => result.PartialColTuple.Add(key, tupleInfo.PartialColTuple[key])); + return result; + } +} + +internal interface IStrataReportParameter +{ + string DimensionId { get; set; } + string AttributeId { get; set; } +} + +internal abstract class StrataSphereAdHocReportParameter : IStrataReportParameter +{ + protected StrataSphereAdHocReportParameter() + { + } + + public string Name { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public string MeasureId { get; set; } + public int DisplayOrder { get; set; } + public bool IsUserEditable { get; set; } + + public bool IsAttributeParameter => string.IsNullOrWhiteSpace(MeasureId); + +} + +public class StrataSphereAdHocScoreDimensionInfo +{ + public Guid DimensionGUID { get; set; } + public string FriendlyName { get; set; } + public string GlobalID { get; set; } + public string AttributeId { get; set; } + public string MDXMemberID { get; set; } + public bool IsRollup { get; set; } + internal Regex ServiceLineRegex = new Regex(@"^Service Line (\d)$", RegexOptions.IgnoreCase); + + // internal string MDXMemberName => AnalysisServicesUtils.GetHierarchyMDXName("Patient Encounter", + // ServiceLineRegex.IsMatch(FriendlyName) && IsRollup + // ? $"{ServiceLineRegex.Replace(FriendlyName, "Service Line Rollup ${1}")}" + // : $"{FriendlyName}{(IsRollup ? " Rollup" : "")}"); + + internal string Name => $"Patient Encounter - {FriendlyName}{(IsRollup ? " Rollup" : "")}"; + + internal StrataSphereAdHocScoreDimensionInfo() + { + MDXMemberID = string.Empty; + IsRollup = false; + } +} + +#endregion + + +#region Other Stuff + +public interface IAdHocReportSectionMeasure //: IAdHocReportSectionItem +{ + string ColumnName { get; set; } + string DisplayFormat { get; } + string CSSClass { get; } + List LinkedSectionGUIDs { get; } + void Hide(); + string MeasureID { get; } + + bool IsPartial { get; } + bool IsAttributeMember { get; } + + eAggregateFunction AggregationTypeEnum { get; } + IAdHocReportSectionMeasure CopyMeasure(); +} + + +public interface ITGuid +{ + Guid Value { get; set; } + bool IsEmpty { get; set; } +} + +public enum eClientReportSectionItemType +{ + Attribute = 0, + Hierarchy = 1, + Measure = 2, + Calculation = 3 +} + +public enum eReportDrilldownStatus +{ + None = 0, + Drilldown = 1, + Drillup = 2 +} + +public enum eClientReportVisibilityStatus +{ + Hidden = 0, + CompletelyVisible = 1, + PartiallyVisible = 2 +} + +public enum eAggregateFunction +{ + Sum = 0, + Count = 1, + Avg = 2, + Min = 3, + Max = 4, + None = 5 +} + + +public interface IAdHocReportSectionAttribute //: IAdHocReportSectionItem +{ + ITGuid AttributeGUIDTyped { get; } + string DimensionID { get; } + string AttributeID { get; } + bool ShowSubtotal { get; set; } + + SortOrder SortOrder { get; } + eClientReportVisibilityStatus VisibilityStatus { get; set; } + eReportDrilldownStatus DrilldownStatus { get; set; } + + string FilterMemberCSV { get; set; } + List FilterMembers { get; set; } + List FilterMembersVisible { get; } +} + +public class ReportTupleInfo +{ + public ReportTupleInfo() + { + this.PartialRowTuple = new Dictionary(); + this.PartialColTuple = new Dictionary(); + } + + private Dictionary _Tuple; + public Dictionary Tuple + { + get + { + return _Tuple; + } + set { _Tuple = value; } + } + + public Dictionary PartialRowTuple { get; set; } + + public Dictionary PartialColTuple { get; set; } + + public string MainMeasureName { get; private set; } + + private IAdHocReportSectionMeasure _MainMeasure; + public IAdHocReportSectionMeasure MainMeasure + { + get { return _MainMeasure; } + set + { + _MainMeasure = value; + MainMeasureName = (value == null) ? string.Empty : value.ColumnName; + } + } + + public string RowMeasureName { get; set; } + + public string ColMeasureName { get; set; } + + public Guid ColMeasureGUID { get; set; } + + public string FormatString { get; set; } + + public int rowIndex { get; set; } + + public int colIndex { get; set; } + + public Guid ColumnSectionGUID { get; set; } + +} + +public class AxisSetting +{ + public string XAxisLabel { get; set; } + public string YAxisLabel { get; set; } + public double? YAxisLowerBound { get; set; } + public double? YAxisUpperBound { get; set; } + public double? YAxisTickInterval { get; set; } + public double? YAxisPlotLineValue { get; set; } + public bool ShowDataLabel { get; set; } + + public override bool Equals(object obj) + { + var config = (AxisSetting)obj; + + if (config == null) return false; + if (config.XAxisLabel != this.XAxisLabel) return false; + if (config.YAxisLabel != this.YAxisLabel) return false; + if (config.YAxisLowerBound != this.YAxisLowerBound) return false; + if (config.YAxisUpperBound != this.YAxisUpperBound) return false; + if (config.YAxisTickInterval != this.YAxisTickInterval) return false; + if (config.YAxisPlotLineValue != this.YAxisPlotLineValue) return false; + if (config.ShowDataLabel != this.ShowDataLabel) return false; + + return true; + } + +} + +public abstract class BaseConfig +{ + public abstract DataTable GetData(object report); + + public abstract string Name { get; } + + public string Title { get; set; } + + public string Description { get; set; } + + public string[] Colors { get; set; } + + public AxisSetting AxisSettings { get; set; } + + public virtual string IconName { get { return ""; } } + public virtual string XType { get { return ""; } } + public virtual string SectionName { get { return ""; } } + public virtual int ColumnNumber { get { return -1; } } + public virtual int RowNumber { get { return -1; } } + public virtual bool YAxisMultiSelect { get { return true; } } + + protected BaseConfig() + { + this.Colors = new string[] { }; + this.AxisSettings = new AxisSetting(); + } + + public override bool Equals(object obj) + { + var config = (BaseConfig)obj; + + if (config == null) return false; + if (config.Title != Title || config.Description != Description) return false; + if (config.Colors.Length != Colors.Length) return false; + if (config.Colors.Any(p => !Colors.Contains(p))) return false; + if (!config.AxisSettings.Equals(this.AxisSettings)) return false; + if (config.GetType().Name != this.GetType().Name) return false; + + return true; + } + +} +#endregion \ No newline at end of file diff --git a/StarterSet API/Starter Set API Validate Endpoint.linq b/StarterSet API/Starter Set API Validate Endpoint.linq new file mode 100644 index 0000000..8e154cf --- /dev/null +++ b/StarterSet API/Starter Set API Validate Endpoint.linq @@ -0,0 +1,96 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + + +private string BaseUrl = @"https://api-prod.sdt.local/starterset-api"; +private string Resource = @"Reports/Populate"; + +void Main() +{ + var client = new RestClient(); + BaseUrl += "/api/v1"; + client.BaseUrl = new Uri(BaseUrl); + DumpEndpoint(client, "prod"); + Resource = @"Reports/Test"; + DumpEndpoint(client, "Test"); + Resource = @"Reports/a281733b-30d8-4d51-2148-08d799ffe4e4/Setup"; + DumpEndpoint(client, Resource); + + Resource = @"Reports/Populate"; + var environments = new[] { "dev", "qa", "training" }.ToList(); + environments.ForEach(env => + { + DumpEnv(client, env); + }); +} + +void DumpEnv(RestClient client, string env) +{ + BaseUrl = $@"https://starterset-api.{env}.k8s.sdt.local"; + BaseUrl += "/api/v1"; + client.BaseUrl = new Uri(BaseUrl); + DumpEndpoint(client, env); +} + +void DumpEndpoint(RestClient client, string env) +{ + var request = new RestRequest(); + request.Method = Method.GET; + request.Resource = Resource; + var response = client.Execute(request); + response.Content.Dump(env); +} + +// Define other methods and classes here \ No newline at end of file diff --git a/StarterSet API/Starter Set API With Report Setup.linq b/StarterSet API/Starter Set API With Report Setup.linq new file mode 100644 index 0000000..80a0e0c --- /dev/null +++ b/StarterSet API/Starter Set API With Report Setup.linq @@ -0,0 +1,908 @@ + + DataGrids + Newtonsoft.Json + RestSharp + RestSharp + Newtonsoft.Json.Converters + Newtonsoft.Json + System.Dynamic + + +private string BaseUrl = +//"https://starterset-api.dev.k8s.sdt.local/api/v1/"; +"https://localhost:44325/api/v1/"; + +void Main() +{ + RestClient client = new RestClient(); + var reports = GetList(client, "Reports"); + + var rpts = reports + .Where(r => r.Name.StartsWith("TL Fiscal Month Test")) + .OrderBy(r => r.Name) + .ToList() + .Select(rpt => new { rpt.Id, rpt.Name, setup = GetList(client, $"Reports\\{rpt.Id}\\Setup") }) + //.Where(x => ((IDictionary)x.setup).ContainsKey("ServiceLines")) + ; + rpts.Dump(nameof(rpts),6); + + var definitions = GetList(client, "Definitions") + .Where(dd => dd.DimensionId == "e18e27ea-52ec-4793-9209-c6259c78474a" + || dd.DimensionId == "Fiscan Month"); + definitions.Dump(); + + /* + var setups = rpts.Select(r => r.setup); + setups.Dump(nameof(setups)); + var serviceLines = setups.Where(x => ((IDictionary)x).ContainsKey("ServiceLines")) + .SelectMany(s => ((List)s.ServiceLines) + .Select(x => x)); + serviceLines.Dump(nameof(serviceLines)); + + var dataSources = setups.SelectMany(s => ((List)s.DataSources) + .Select(x => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(x)))) + .GroupBy(ds => ds.DataSourceGuid, (g, d) => d.First()); + dataSources.Dump(nameof(dataSources)); + // var globalParameters = setups.SelectMany(s => ((List)s.Parameters) + // .Select(x => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(x)))); + // globalParameters.Dump(nameof(globalParameters)); + var sections = setups.SelectMany(s => ((List)s.Sections) + .Select(x => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(x)))); + var attributes = sections.SelectMany(s => s.Attributes) + .Select(x => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(x))); + attributes.Dump(nameof(attributes)); + var attrParms = attributes.SelectMany(a => a.Parameters); + attrParms.Dump(nameof(attrParms)); + var calculations = sections.SelectMany(s => s.Calculations) + .Select(x => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(x))); + calculations.Dump(nameof(calculations)); + */ +} + +dynamic GetList(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var converter = new ExpandoObjectConverter(); + return JsonConvert.DeserializeObject(client.Execute(request).Content, converter); +} + +//void other() +//{ +// StandardDefinitionMappings.Select(sdm => new +// { +// sdm.MappingId, +// sdm.StandardDefinitionGUID, +// sdm.StandardDefinitionType, +// MappingMemberValue = JsonConvert.DeserializeObject(sdm.MappingMemberValue) +// }).Dump("StandardDefinitionMappings"); +// +// REReports.Join(REDSCubeReportParameters, +// r => r.ReportGUID, +// p => p.ReportGUID, +// (r, p) => new ReportInfo(p.ParameterXML) +// { +// Report = r.Name, +// DimensionID = p.DimensionID, +// AttributeID = p.AttributeID +// }).Dump("Cube Reports"); +// +// REReports.Join(REClientReportParameters, +// r => r.ReportGUID, +// p => p.ReportGUID, +// (r, p) => new ReportInfo(p.ParameterXML) +// { +// Report = r.Name, +// DimensionID = p.DimensionID, +// AttributeID = p.AttributeID +// }).Dump("Client Reports"); +//} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content, + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Error.Message.Dump(); + args.ErrorContext.Handled = true; + } + }); +} + +void stuff(RestClient client) +{ + client.BaseUrl = new Uri(BaseUrl + "Definitions"); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var definitions = JsonConvert.DeserializeObject>(client.Execute(request).Content); + definitions.Where(d => d.DimensionGuid == new Guid("6EF6B1F7-A50C-4198-8866-140BB82E2DDA")).Dump("Definitions"); + + client.BaseUrl = new Uri(BaseUrl + "MDXScoreToCube"); + var mdx = JsonConvert.DeserializeObject>(client.Execute(request).Content); + mdx.Dump("MDX"); + + client.BaseUrl = new Uri(BaseUrl + "Reports"); + var reports = JsonConvert.DeserializeObject>(client.Execute(request).Content); + reports.Dump("Reports"); + + var reportSetupUrl = new Uri(BaseUrl + "Reports/{0}/Setup"); + reports.Where(r => r.Id == new Guid("a4a12e21-954b-4889-d5c8-08d71f2ff590")).ToList().ForEach(r => + { + client.BaseUrl = new Uri(BaseUrl + $"Reports/{r.Id}"); + var rpt = JsonConvert.DeserializeObject(client.Execute(request).Content); + rpt.DefinitionIds.ForEach(d => + { + client.BaseUrl = new Uri(BaseUrl + $"Defintions/{d}"); + var definition = JsonConvert.DeserializeObject>(client.Execute(request).Content); + definition.Dump($"Report {r.Name} Definition {d}"); + }); + }); + +} + +// Define other methods and classes here + +public class ReportInfo +{ + public string Report { get; set; } + public string DimensionID { get; set; } + public string AttributeID { get; set; } + public string ParameterXML { get; set; } + + internal XmlDocument doc; + public string Parameter { get; set; } + public ReportInfo(string parameterXML) + { + ParameterXML = parameterXML; + var parameterXml = ParameterXML = $"{ParameterXML}" + .RemoveAllNamespacesAsString() + .Replace("string>", "valueId>") + .Replace("", "") + .Replace("<_", "<").Replace("( + JsonConvert.SerializeXmlNode(doc.SelectSingleNode("root") + ) + ) + , + Newtonsoft.Json.Formatting.Indented); + } +} + +public class StrataSphereMappingValues +{ + public string HierarchyGUID { get; set; } + public string DimensionGUID { get; set; } + public List values { get; set; } + public List mappings { get; set; } + public List hierarchyPaths { get; set; } + + public StrataSphereMappingValues() + { + mappings = new List(); + } +} + +public class MappingValue +{ + public string id { get; set; } + public string displayHierarchyName { get; set; } + public string text { get; set; } + public string name { get; set; } + public List attributeValues { get; set; } + public List hierarchyPaths { get; set; } + + public MappingValue() + { + attributeValues = new List(); + hierarchyPaths = new List(); + } +} + +public enum eStrataSphereItemCategory +{ + Report, + Dashboard +} + +public enum StrataSphereReportEnum +{ + Report, + DSCubeReport, + SQLReport, + ClientReport +} + +public class ReportDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public eStrataSphereItemCategory Category => eStrataSphereItemCategory.Report; + public string Tagline => + $"Report | {Module} | {DateCreated.ToString("MMM-dd-YYYY")} | {DownloadCount} downloads"; + + public StrataSphereReportEnum ReportType { get; set; } + public string Module { get; set; } + public string MinJazzVersion { get; set; } + public string MaxJazzVersion { get; set; } + public string ReportSetupJson { get; set; } + public List DefinitionIds { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + public int DownloadCount { get; set; } + + public ReportDto() + { + ReportSetupJson = "{}"; + DefinitionIds = new List(); + } +} + +public class DefinitionDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public Guid HierarchyGuid { get; set; } + public Guid DimensionGuid { get; set; } + public Guid AttributeGuid { get; set; } + public string HierarchyId { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } +} + +public enum MDXMemberIDTypeEnum +{ + Attribute, + Name, + Text, + Id, + HierarchyPath +} + +public enum MDXFormatTypeEnum +{ + None, + MDX, + Hierarchy, + MDXMemberId +} + +public class MDXScoreToCubeDto +{ + public string OrgPin { get; set; } + public Guid DatabaseGuid { get; set; } + public string ScoreDimensionName { get; set; } + public string ScoreHierarchyName { get; set; } + public string CubeDimensionName { get; set; } + public string CubeHierarchyName { get; set; } + public MDXMemberIDTypeEnum MDXMemberIDType { get; set; } + public MDXFormatTypeEnum MDXFormatType { get; set; } +} + +public class ValueIDArray +{ + public List valueId { get; set; } +} + +public class DSCubeSearchCondition +{ + public string FilterOp { get; set; } + public string SearchType { get; set; } + public string Value2 { get; set; } + public string Value { get; set; } + public ValueIDArray ValueIDArray { get; set; } +} + +public class SearchConditions +{ + public DSCubeSearchCondition DSCubeSearchCondition { get; set; } +} + +public class DSCubeSearchParameterValue +{ + public string ParameterGUID { get; set; } + public string ParameterValueGUID { get; set; } + public SearchConditions SearchConditions { get; set; } +} + +public class Root +{ + public DSCubeSearchParameterValue DSCubeSearchParameterValue { get; set; } +} + +public class RootObject +{ + public Root root { get; set; } +} + +#region StrataSphereAdHocReportSetup + +public interface IStrataSphereAdHocReportSectionItem +{ + string Name { get; set; } + bool IsOnChartXAxis { get; set; } + bool IsOnChartYAxis { get; set; } +} + +internal class StrataSphereAdHocReportAttribute : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportAttribute() + { + + } + + public string AttributeId { get; set; } + public string DimensionId { get; set; } + public int Index { get; set; } + public string Name { get; set; } + public IList FilterMembers { get; set; } + public int VisibilityStatusValue { get; set; } + public bool ShowSubtotal { get; set; } + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + // section level filters + public List Parameters { get; set; } = new List(); + //public List Parameters { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportCalculation : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportCalculation() + { + } + public string Name { get; set; } + public string CalcType { get; set; } + public int DisplayOrder { get; set; } + public string DisplayFormat { get; set; } + public int ColumnWidth { get; set; } + public string CalculationJson { get; set; } + public string CssClass { get; set; } + public bool IsAttributeMember { get; set; } + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + public List ConditionalFormats { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportConditionalFormat +{ + public StrataSphereAdHocReportConditionalFormat() + { + + } + public string Comment { get; set; } + public int DisplayOrder { get; set; } + public ReportTupleInfo ColumnTupleInfo { get; set; } + public string CssClass { get; set; } + public string ValueToCompareAsString { get; set; } + public int OperatorValue { get; set; } +} + +internal class StrataSphereAdHocReportConfig +{ + public string Title { get; set; } + public string Description { get; set; } + public string[] Colors { get; set; } + public AxisSetting AxisSettings { get; set; } + public string XType { get; set; } + public bool YAxisMultiSelect { get; set; } + public Guid XAxisSectionItemGuid { get; set; } + public List YAxisSectionItemGuids { get; set; } = new List(); + + public StrataSphereAdHocReportConfig(BaseConfig source) + { + if (source == null) return; + Title = source.Title; + Description = source.Description; + Colors = source.Colors; + AxisSettings = source.AxisSettings; + XType = source.XType; + YAxisMultiSelect = source.YAxisMultiSelect; + } + + public BaseConfig GetChartConfig() + { + var chartConfig = default(BaseConfig); + /* + // Try decoding the xType by the name first + var asm = typeof(AreaConfig).Assembly; + var type = asm.GetType($"{asm.GetName().Name}.Reporting.ChartConfigs.{XType}"); + if (type != null) + { + chartConfig = (BaseConfig)Activator.CreateInstance(type); + } + else // if that failed then use the hard coded selector, this is an issue if new types are supported + { + switch (XType) + { + case "AreaConfig": + chartConfig = new AreaConfig(); + break; + case "BarConfig": + chartConfig = new BarConfig(); + break; + case "BubbleConfig": + chartConfig = new BubbleConfig(); + break; + case "ColumnConfig": + chartConfig = new ColumnConfig(); + break; + case "ComboColumnAndLineConfig": + chartConfig = new ComboColumnAndLineConfig(); + break; + case "ComboColumnAndLineWithSecondaryAxisConfig": + chartConfig = new ComboColumnAndLineWithSecondaryAxisConfig(); + break; + case "DonutConfig": + chartConfig = new DonutConfig(); + break; + case "LineConfig": + chartConfig = new LineConfig(); + break; + case "PieConfig": + chartConfig = new PieConfig(); + break; + case "ScatterConfig": + chartConfig = new ScatterConfig(); + break; + case "SplineConfig": + chartConfig = new SplineConfig(); + break; + case "StackedBarConfig": + chartConfig = new StackedBarConfig(); + break; + case "StackedBarPercentConfig": + chartConfig = new StackedBarPercentConfig(); + break; + case "StackedColumnConfig": + chartConfig = new StackedColumnConfig(); + break; + case "StackedColumnPercentConfig": + chartConfig = new StackedColumnPercentConfig(); + break; + } + } + */ + if (chartConfig == null) return chartConfig; + chartConfig.Title = Title; + chartConfig.Description = Description; + chartConfig.Colors = Colors; + chartConfig.AxisSettings = AxisSettings; + // if (chartConfig is XYConfig xyConfig) + // { + // xyConfig.XAxisSectionItemGuid = XAxisSectionItemGuid; + // xyConfig.YAxisSectionItemGuids.AddRange(YAxisSectionItemGuids); + // } + return chartConfig; + } + +} + +internal class StrataSphereAdHocReportDataSource +{ + public StrataSphereAdHocReportDataSource() + { + + } + public Guid DataSourceGuid { get; set; } + public string Name { get; set; } + public int DataSourceType { get; set; } +} + +internal class StrataSphereAdHocReportMeasure : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportMeasure() + { + + } + public string MeasureId { get; set; } + public string Name { get; set; } + public int Index { get; set; } + + public string DisplayFormat { get; set; } + public int ColumnWidth { get; set; } + + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + // section level filters + public List Parameters { get; set; } = new List(); + + public List ConditionalFormats { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportSection +{ + public StrataSphereAdHocReportSection() + { + + } + public string Name { get; set; } + public bool IsOnColumn { get; set; } + public int DisplayOrder { get; set; } + public bool IsTimeRelative { get; set; } + + public bool IsFinancialReportSectionHidable { get; set; } + public bool IsMergingRepeatHeader { get; set; } + public bool IsSpaceAbove { get; set; } + public bool IsHidden { get; set; } + + public string DisplayLabel { get; set; } + public bool ShowSectionLabel { get; set; } + public bool ShowGrandTotal { get; set; } + public bool IsAutoNameFilter { get; set; } + public bool ShowMargin { get; set; } + + public List Attributes { get; set; } = new List(); + + public List Measures { get; set; } = new List(); + + public List Calculations { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportSetup +{ + public string Style { get; set; } + + public StrataSphereAdHocReportSortArgs SortArgs { get; set; } + + public List DataSources { get; set; } = new List(); + + public StrataSphereAdHocReportConfig ChartConfig { get; set; } = null; + + public List Sections { get; set; } = new List(); + + public List Parameters { get; set; } = new List(); + + public List ServiceLines { get; set; } = + new List(); + +} + +public class StrataSphereAdHocReportSortArgs +{ + public StrataSphereAdHocReportTupleInfo TupleInfo { get; set; } + public bool IsAscending { get; set; } + public int SortCount { get; set; } + public int Top { get; set; } + public bool IsTopPercent { get; set; } + public bool IsIncludeAllOthers { get; set; } + + public StrataSphereAdHocReportSortArgs() + { + TupleInfo = new StrataSphereAdHocReportTupleInfo(); + } +} + +public class StrataSphereAdHocReportTupleInfo +{ + public Dictionary PartialRowTuple { get; set; } + public Dictionary PartialColTuple { get; set; } + public string MainMeasureName { get; private set; } + public string RowMeasureName { get; set; } + public string ColMeasureName { get; set; } + public Guid ColMeasureGUID { get; set; } + public string FormatString { get; set; } + public int rowIndex { get; set; } + public int colIndex { get; set; } + public Guid ColumnSectionGUID { get; set; } + public IAdHocReportSectionMeasure MainMeasure { get; set; } + + public StrataSphereAdHocReportTupleInfo() + { + PartialRowTuple = new Dictionary(); + PartialColTuple = new Dictionary(); + ColumnSectionGUID = Guid.Empty; + ColMeasureGUID = Guid.Empty; + } + + public StrataSphereAdHocReportTupleInfo(ReportTupleInfo tupleInfo) + : this() + { + if (tupleInfo == null) return; + tupleInfo.PartialRowTuple.Keys.ToList() + .ForEach(key => PartialRowTuple.Add(key, tupleInfo.PartialRowTuple[key])); + tupleInfo.PartialColTuple.Keys.ToList() + .ForEach(key => PartialColTuple.Add(key, tupleInfo.PartialColTuple[key])); + //MainMeasure = tupleInfo.MainMeasure; + MainMeasureName = tupleInfo.MainMeasureName; + RowMeasureName = tupleInfo.RowMeasureName; + ColMeasureName = tupleInfo.ColMeasureName; + ColMeasureGUID = tupleInfo.ColMeasureGUID; + FormatString = tupleInfo.FormatString; + rowIndex = tupleInfo.rowIndex; + colIndex = tupleInfo.colIndex; + ColumnSectionGUID = tupleInfo.ColumnSectionGUID; + } + + public static implicit operator ReportTupleInfo(StrataSphereAdHocReportTupleInfo tupleInfo) + { + if (tupleInfo == null) return null; + var result = new ReportTupleInfo + { + PartialRowTuple = new Dictionary(), + PartialColTuple = new Dictionary(), + MainMeasure = tupleInfo.MainMeasure?.CopyMeasure(), + RowMeasureName = tupleInfo.RowMeasureName, + ColMeasureName = tupleInfo.ColMeasureName, + ColMeasureGUID = tupleInfo.ColMeasureGUID, + FormatString = tupleInfo.FormatString, + rowIndex = tupleInfo.rowIndex, + colIndex = tupleInfo.colIndex, + ColumnSectionGUID = tupleInfo.ColumnSectionGUID + }; + tupleInfo.PartialRowTuple.Keys.ToList() + .ForEach(key => result.PartialRowTuple.Add(key, tupleInfo.PartialRowTuple[key])); + tupleInfo.PartialColTuple.Keys.ToList() + .ForEach(key => result.PartialColTuple.Add(key, tupleInfo.PartialColTuple[key])); + return result; + } +} + +internal interface IStrataReportParameter +{ + string DimensionId { get; set; } + string AttributeId { get; set; } +} + +internal abstract class StrataSphereAdHocReportParameter : IStrataReportParameter +{ + protected StrataSphereAdHocReportParameter() + { + } + + public string Name { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public string MeasureId { get; set; } + public int DisplayOrder { get; set; } + public bool IsUserEditable { get; set; } + + public bool IsAttributeParameter => string.IsNullOrWhiteSpace(MeasureId); + +} + +public class StrataSphereAdHocScoreDimensionInfo +{ + public Guid DimensionGUID { get; set; } + public string FriendlyName { get; set; } + public string GlobalID { get; set; } + public string AttributeId { get; set; } + public string MDXMemberID { get; set; } + public bool IsRollup { get; set; } + internal Regex ServiceLineRegex = new Regex(@"^Service Line (\d)$", RegexOptions.IgnoreCase); + + // internal string MDXMemberName => AnalysisServicesUtils.GetHierarchyMDXName("Patient Encounter", + // ServiceLineRegex.IsMatch(FriendlyName) && IsRollup + // ? $"{ServiceLineRegex.Replace(FriendlyName, "Service Line Rollup ${1}")}" + // : $"{FriendlyName}{(IsRollup ? " Rollup" : "")}"); + + internal string Name => $"Patient Encounter - {FriendlyName}{(IsRollup ? " Rollup" : "")}"; + + internal StrataSphereAdHocScoreDimensionInfo() + { + MDXMemberID = string.Empty; + IsRollup = false; + } +} + +#endregion + + +#region Other Stuff + +public interface IAdHocReportSectionMeasure //: IAdHocReportSectionItem +{ + string ColumnName { get; set; } + string DisplayFormat { get; } + string CSSClass { get; } + List LinkedSectionGUIDs { get; } + void Hide(); + string MeasureID { get; } + + bool IsPartial { get; } + bool IsAttributeMember { get; } + + eAggregateFunction AggregationTypeEnum { get; } + IAdHocReportSectionMeasure CopyMeasure(); +} + + +public interface ITGuid +{ + Guid Value { get; set; } + bool IsEmpty { get; set; } +} + +public enum eClientReportSectionItemType +{ + Attribute = 0, + Hierarchy = 1, + Measure = 2, + Calculation = 3 +} + +public enum eReportDrilldownStatus +{ + None = 0, + Drilldown = 1, + Drillup = 2 +} + +public enum eClientReportVisibilityStatus +{ + Hidden = 0, + CompletelyVisible = 1, + PartiallyVisible = 2 +} + +public enum eAggregateFunction +{ + Sum = 0, + Count = 1, + Avg = 2, + Min = 3, + Max = 4, + None = 5 +} + + +public interface IAdHocReportSectionAttribute //: IAdHocReportSectionItem +{ + ITGuid AttributeGUIDTyped { get; } + string DimensionID { get; } + string AttributeID { get; } + bool ShowSubtotal { get; set; } + + SortOrder SortOrder { get; } + eClientReportVisibilityStatus VisibilityStatus { get; set; } + eReportDrilldownStatus DrilldownStatus { get; set; } + + string FilterMemberCSV { get; set; } + List FilterMembers { get; set; } + List FilterMembersVisible { get; } +} + +public class ReportTupleInfo +{ + public ReportTupleInfo() + { + this.PartialRowTuple = new Dictionary(); + this.PartialColTuple = new Dictionary(); + } + + private Dictionary _Tuple; + public Dictionary Tuple + { + get + { + return _Tuple; + } + set { _Tuple = value; } + } + + public Dictionary PartialRowTuple { get; set; } + + public Dictionary PartialColTuple { get; set; } + + public string MainMeasureName { get; private set; } + + private IAdHocReportSectionMeasure _MainMeasure; + public IAdHocReportSectionMeasure MainMeasure + { + get { return _MainMeasure; } + set + { + _MainMeasure = value; + MainMeasureName = (value == null) ? string.Empty : value.ColumnName; + } + } + + public string RowMeasureName { get; set; } + + public string ColMeasureName { get; set; } + + public Guid ColMeasureGUID { get; set; } + + public string FormatString { get; set; } + + public int rowIndex { get; set; } + + public int colIndex { get; set; } + + public Guid ColumnSectionGUID { get; set; } + +} + +public class AxisSetting +{ + public string XAxisLabel { get; set; } + public string YAxisLabel { get; set; } + public double? YAxisLowerBound { get; set; } + public double? YAxisUpperBound { get; set; } + public double? YAxisTickInterval { get; set; } + public double? YAxisPlotLineValue { get; set; } + public bool ShowDataLabel { get; set; } + + public override bool Equals(object obj) + { + var config = (AxisSetting)obj; + + if (config == null) return false; + if (config.XAxisLabel != this.XAxisLabel) return false; + if (config.YAxisLabel != this.YAxisLabel) return false; + if (config.YAxisLowerBound != this.YAxisLowerBound) return false; + if (config.YAxisUpperBound != this.YAxisUpperBound) return false; + if (config.YAxisTickInterval != this.YAxisTickInterval) return false; + if (config.YAxisPlotLineValue != this.YAxisPlotLineValue) return false; + if (config.ShowDataLabel != this.ShowDataLabel) return false; + + return true; + } + +} + +public abstract class BaseConfig +{ + public abstract DataTable GetData(object report); + + public abstract string Name { get; } + + public string Title { get; set; } + + public string Description { get; set; } + + public string[] Colors { get; set; } + + public AxisSetting AxisSettings { get; set; } + + public virtual string IconName { get { return ""; } } + public virtual string XType { get { return ""; } } + public virtual string SectionName { get { return ""; } } + public virtual int ColumnNumber { get { return -1; } } + public virtual int RowNumber { get { return -1; } } + public virtual bool YAxisMultiSelect { get { return true; } } + + protected BaseConfig() + { + this.Colors = new string[] { }; + this.AxisSettings = new AxisSetting(); + } + + public override bool Equals(object obj) + { + var config = (BaseConfig)obj; + + if (config == null) return false; + if (config.Title != Title || config.Description != Description) return false; + if (config.Colors.Length != Colors.Length) return false; + if (config.Colors.Any(p => !Colors.Contains(p))) return false; + if (!config.AxisSettings.Equals(this.AxisSettings)) return false; + if (config.GetType().Name != this.GetType().Name) return false; + + return true; + } + +} +#endregion \ No newline at end of file diff --git a/StarterSet API/Starter Set API test.linq b/StarterSet API/Starter Set API test.linq new file mode 100644 index 0000000..7c7422d --- /dev/null +++ b/StarterSet API/Starter Set API test.linq @@ -0,0 +1,1172 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod 20190708.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + + +private string BaseUrl = "https://api-prod.sdt.local/StrataSphere.Web.API.Service/api/v1/"; + +void Main() +{ + RestClient client = new RestClient(); + var definitions = GetList(client, "Definitions"); + var hierarchies = (from scoreHierarchy in ViewScoreHierarchy select new { scoreHierarchy.HierarchyGUID, scoreHierarchy.FriendlyName, scoreHierarchy.DimensionGUID}).ToList() + .Where(sh => definitions.Select(d => d.HierarchyGuid).Contains(sh.HierarchyGUID)) + .GroupBy(sh => sh.HierarchyGUID, (grp, data) => new { HierarchyGUID = grp, DimensionGUID = data.First().DimensionGUID, FriendlyName = data.First().FriendlyName }); + //179B6541-2285-4196-4209-08D7469CC7F2 + definitions + //.Where(d => d.HierarchyId == "UB Revenue Code") + .Where(d => d.DimensionId == "Patient Encounter") + .OrderBy(d => d.DimensionId).ThenBy(d => d.AttributeId).ThenBy(d => d.Name).Dump("Definitions"); + hierarchies.Dump("Hierarchies"); + + var mdx = GetList(client, "MDXScoreToCube"); + mdx + .Where(m => m.OrgPin == "0430") + //.Where(m => m.CubeDimensionName.Contains("Patient")) + .OrderBy(m => m.ScoreHierarchyName) + .ThenBy(m => m.OrgPin).Dump("MDX Score to Cube"); +} + +void other() +{ + StandardDefinitionMappings.Select(sdm => new + { + sdm.MappingId, + sdm.StandardDefinitionGUID, + sdm.StandardDefinitionType, + MappingMemberValue = JsonConvert.DeserializeObject(sdm.MappingMemberValue) + }).Dump("StandardDefinitionMappings"); + + REReports.Join(REDSCubeReportParameters, + r => r.ReportGUID, + p => p.ReportGUID, + (r, p) => new ReportInfo(p.ParameterXML) + { + Report = r.Name, + DimensionID = p.DimensionID, + AttributeID = p.AttributeID + }).Dump("Cube Reports"); + + REReports.Join(REClientReportParameters, + r => r.ReportGUID, + p => p.ReportGUID, + (r, p) => new ReportInfo(p.ParameterXML) + { + Report = r.Name, + DimensionID = p.DimensionID, + AttributeID = p.AttributeID + }).Dump("Client Reports"); +} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content); +} + +void stuff(RestClient client) +{ + client.BaseUrl = new Uri(BaseUrl + "Definitions"); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var definitions = JsonConvert.DeserializeObject>(client.Execute(request).Content); + definitions.Where(d => d.DimensionGuid == new Guid("6EF6B1F7-A50C-4198-8866-140BB82E2DDA")).Dump("Definitions"); + + client.BaseUrl = new Uri(BaseUrl + "MDXScoreToCube"); + var mdx = JsonConvert.DeserializeObject>(client.Execute(request).Content); + mdx.Dump("MDX"); + + client.BaseUrl = new Uri(BaseUrl + "Reports"); + var reports = JsonConvert.DeserializeObject>(client.Execute(request).Content); + reports.Dump("Reports"); + + var reportSetupUrl = new Uri(BaseUrl + "Reports/{0}/Setup"); + reports.Where(r => r.Id == new Guid("a4a12e21-954b-4889-d5c8-08d71f2ff590")).ToList().ForEach(r => + { + client.BaseUrl = new Uri(BaseUrl + $"Reports/{r.Id}"); + var rpt = JsonConvert.DeserializeObject(client.Execute(request).Content); + rpt.DefinitionIds.ForEach(d => + { + client.BaseUrl = new Uri(BaseUrl + $"Defintions/{d}"); + var definition = JsonConvert.DeserializeObject>(client.Execute(request).Content); + definition.Dump($"Report {r.Name} Definition {d}"); + }); + }); + +} + +// Define other methods and classes here + +public class ReportInfo +{ + public string Report { get; set; } + public string DimensionID { get; set; } + public string AttributeID { get; set; } + public string ParameterXML { get; set; } + + internal XmlDocument doc; + public string Parameter { get; set; } + public ReportInfo(string parameterXML) + { + ParameterXML = parameterXML; + var parameterXml = ParameterXML = $"{ParameterXML}" + .RemoveAllNamespacesAsString() + .Replace("string>", "valueId>") + .Replace("", "") + .Replace("<_", "<").Replace("( + JsonConvert.SerializeXmlNode(doc.SelectSingleNode("root") + ) + ) + , + Newtonsoft.Json.Formatting.Indented); + } +} + +public class StrataSphereMappingValues +{ + public string HierarchyGUID { get; set; } + public string DimensionGUID { get; set; } + public List values { get; set; } + public List mappings { get; set; } + public List hierarchyPaths { get; set; } + + public StrataSphereMappingValues() + { + mappings = new List(); + } +} + +public class MappingValue +{ + public string id { get; set; } + public string displayHierarchyName { get; set; } + public string text { get; set; } + public string name { get; set; } + public List attributeValues { get; set; } + public List hierarchyPaths { get; set; } + + public MappingValue() + { + attributeValues = new List(); + hierarchyPaths = new List(); + } +} + +public enum eStrataSphereItemCategory +{ + Report, + Dashboard +} + +public enum StrataSphereReportEnum +{ + Report, + DSCubeReport, + SQLReport, + ClientReport +} + +public class ReportDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public eStrataSphereItemCategory Category => eStrataSphereItemCategory.Report; + public string Tagline => + $"Report | {Module} | {DateCreated.ToString("MMM-dd-YYYY")} | {DownloadCount} downloads"; + + public StrataSphereReportEnum ReportType { get; set; } + public string Module { get; set; } + public string MinJazzVersion { get; set; } + public string MaxJazzVersion { get; set; } + public string ReportSetupJson { get; set; } + public List DefinitionIds { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + public int DownloadCount { get; set; } + + public ReportDto() + { + ReportSetupJson = "{}"; + DefinitionIds = new List(); + } +} + +public class DefinitionDto +{ + /// + /// Definition Guid in StrataSphere + /// + /// 00000000-0000-0000-0000-000000000000 + public Guid Id { get; set; } + + /// + /// The name of the report + /// + /// TOP 10 DRGs BY SERVICE LINE + public string Name { get; set; } + + /// + /// A short description of the definition's content + /// + /// Top 10 DRGs by Service Line filtered per service line rollup + public string Description { get; set; } + + /// + /// The type of report (i.e. PatientPopulation, Metric) + /// + /// PatientPopulation + public Guid HierarchyGuid { get; set; } + + /// + /// The type of report (i.e. PatientPopulation, Metric) + /// + /// PatientPopulation + public Guid DimensionGuid { get; set; } + + /// + /// The Value of the Object Type + /// + /// All Cause 30 Day Readmits + public Guid AttributeGuid { get; set; } + + /// + /// The string of the Definition's dimension Id + /// + /// [Patient Encounter] + public string HierarchyId { get; set; } + + /// + /// The string of the Definition's dimension Id + /// + /// [Patient Encounter] + public string DimensionId { get; set; } + + /// + /// The string of the Definition's attribute Id + /// + /// [Patient Encounter].[Service Line Strata Decision] + public string AttributeId { get; set; } + + /// + /// When the definition was uploaded to StrataSphere + /// + public DateTime DateCreated { get; set; } + + /// + /// When the definition was last updated in StrataSphere + /// + public DateTime DateLastModified { get; set; } + +} + +public enum MDXMemberIDTypeEnum +{ + Attribute, + Name, + Text, + Id, + HierarchyPath +} + +public enum MDXFormatTypeEnum +{ + None, + MDX, + Hierarchy, + MDXMemberId +} + +public class MDXScoreToCubeDto +{ + /// + /// The orgpin or the item + /// + /// 0000 + public string OrgPin { get; set; } + + /// + /// The database guid of the item + /// + /// 00000000-0000-0000-0000-000000000000 + public Guid DatabaseGuid { get; set; } + + /// + /// The Score Dimension Name of the item + /// + /// Patient Type Rollup + public string ScoreDimensionName { get; set; } + + /// + /// The Score Hierarchy Name of the item + /// + /// Patient Type Rollup + public string ScoreHierarchyName { get; set; } + + /// + /// The Cube Dimension Name of the item + /// + /// Patient Type + public string CubeDimensionName { get; set; } + + /// + /// The Cube Hierarchy Name of the item + /// + /// Rollup + public string CubeHierarchyName { get; set; } + + /// + /// Indicates if the MDX should use the Attribute, Name, or Text value + /// + public MDXMemberIDTypeEnum MDXMemberIDType { get; set; } + + public MDXFormatTypeEnum MDXFormatType { get; set; } + +} + +public class ValueIDArray +{ + public List valueId { get; set; } +} + +public class DSCubeSearchCondition +{ + public string FilterOp { get; set; } + public string SearchType { get; set; } + public string Value2 { get; set; } + public string Value { get; set; } + public ValueIDArray ValueIDArray { get; set; } +} + +public class SearchConditions +{ + public DSCubeSearchCondition DSCubeSearchCondition { get; set; } +} + +public class DSCubeSearchParameterValue +{ + public string ParameterGUID { get; set; } + public string ParameterValueGUID { get; set; } + public SearchConditions SearchConditions { get; set; } +} + +public class Root +{ + public DSCubeSearchParameterValue DSCubeSearchParameterValue { get; set; } +} + +public class RootObject +{ + public Root root { get; set; } +} + +#region StrataSphereAdHocReportSetup + +public interface IStrataSphereAdHocReportSectionItem +{ + string Name { get; set; } + bool IsOnChartXAxis { get; set; } + bool IsOnChartYAxis { get; set; } +} + +internal class StrataSphereAdHocReportAttribute : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportAttribute() + { + + } + + public StrataSphereAdHocReportAttribute(IAdHocReportSectionAttribute attribute) + { + AttributeId = attribute.AttributeID; + DimensionId = attribute.DimensionID; + Index = attribute.DisplayOrder; + Name = attribute.Name; + FilterMembers = attribute.FilterMembers; + VisibilityStatusValue = (int)attribute.VisibilityStatus; + ShowSubtotal = attribute.ShowSubtotal; + } + + public string AttributeId { get; set; } + public string DimensionId { get; set; } + public int Index { get; set; } + public string Name { get; set; } + public IList FilterMembers { get; set; } + public int VisibilityStatusValue { get; set; } + public bool ShowSubtotal { get; set; } + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + // section level filters + public List Parameters { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportCalculation : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportCalculation() + { + } + + public StrataSphereAdHocReportCalculation(IAdHocReportSectionCalculation calculation) + { + Name = calculation.Name; + CalcType = calculation.CalculationType.ID; + DisplayOrder = calculation.DisplayOrder; + ColumnWidth = calculation.ColumnWidth; + DisplayFormat = calculation.DisplayFormat; + CalculationJson = JsonConvert.SerializeObject(calculation.CalculationType); + CssClass = calculation.CSSClass; + IsAttributeMember = calculation.IsAttributeMember; + } + + public string Name { get; set; } + public string CalcType { get; set; } + public int DisplayOrder { get; set; } + public string DisplayFormat { get; set; } + public int ColumnWidth { get; set; } + public string CalculationJson { get; set; } + public string CssClass { get; set; } + public bool IsAttributeMember { get; set; } + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + public List ConditionalFormats { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportConditionalFormat +{ + public StrataSphereAdHocReportConditionalFormat() + { + + } + + public StrataSphereAdHocReportConditionalFormat(IAdHocConditionalFormat conditionalFormat) + { + DisplayOrder = conditionalFormat.DisplayOrder; + Comment = conditionalFormat.Comment; + ColumnTupleInfo = conditionalFormat.ColumnTupleInfo; + } + + public string Comment { get; set; } + public int DisplayOrder { get; set; } + public ReportTupleInfo ColumnTupleInfo { get; set; } + public string CssClass { get; set; } + public string ValueToCompareAsString { get; set; } + public int OperatorValue { get; set; } +} + +internal class StrataSphereAdHocReportConfig +{ + public string Title { get; set; } + public string Description { get; set; } + public string[] Colors { get; set; } + public AxisSetting AxisSettings { get; set; } + public string XType { get; set; } + public bool YAxisMultiSelect { get; set; } + public Guid XAxisSectionItemGuid { get; set; } + public List YAxisSectionItemGuids { get; set; } = new List(); + + public StrataSphereAdHocReportConfig(BaseConfig source) + { + if (source == null) return; + Title = source.Title; + Description = source.Description; + Colors = source.Colors; + AxisSettings = source.AxisSettings; + XType = source.XType; + YAxisMultiSelect = source.YAxisMultiSelect; + } + + public BaseConfig GetChartConfig() + { + var chartConfig = default(BaseConfig); + // Try decoding the xType by the name first + var asm = typeof(AreaConfig).Assembly; + var type = asm.GetType($"{asm.GetName().Name}.Reporting.ChartConfigs.{XType}"); + if (type != null) + { + chartConfig = (BaseConfig)Activator.CreateInstance(type); + } + else // if that failed then use the hard coded selector, this is an issue if new types are supported + { + switch (XType) + { + case "AreaConfig": + chartConfig = new AreaConfig(); + break; + case "BarConfig": + chartConfig = new BarConfig(); + break; + case "BubbleConfig": + chartConfig = new BubbleConfig(); + break; + case "ColumnConfig": + chartConfig = new ColumnConfig(); + break; + case "ComboColumnAndLineConfig": + chartConfig = new ComboColumnAndLineConfig(); + break; + case "ComboColumnAndLineWithSecondaryAxisConfig": + chartConfig = new ComboColumnAndLineWithSecondaryAxisConfig(); + break; + case "DonutConfig": + chartConfig = new DonutConfig(); + break; + case "LineConfig": + chartConfig = new LineConfig(); + break; + case "PieConfig": + chartConfig = new PieConfig(); + break; + case "ScatterConfig": + chartConfig = new ScatterConfig(); + break; + case "SplineConfig": + chartConfig = new SplineConfig(); + break; + case "StackedBarConfig": + chartConfig = new StackedBarConfig(); + break; + case "StackedBarPercentConfig": + chartConfig = new StackedBarPercentConfig(); + break; + case "StackedColumnConfig": + chartConfig = new StackedColumnConfig(); + break; + case "StackedColumnPercentConfig": + chartConfig = new StackedColumnPercentConfig(); + break; + } + } + + if (chartConfig == null) return chartConfig; + chartConfig.Title = Title; + chartConfig.Description = Description; + chartConfig.Colors = Colors; + chartConfig.AxisSettings = AxisSettings; + if (chartConfig is XYConfig xyConfig) + { + xyConfig.XAxisSectionItemGuid = XAxisSectionItemGuid; + xyConfig.YAxisSectionItemGuids.AddRange(YAxisSectionItemGuids); + } + return chartConfig; + } + +} + +internal class StrataSphereAdHocReportDataSource +{ + public StrataSphereAdHocReportDataSource() + { + + } + + public StrataSphereAdHocReportDataSource(IDataSourceLink dataSourceLink) + { + DataSourceGuid = dataSourceLink.DataSourceGUID; + Name = dataSourceLink.DataSourceProvider.Name; + DataSourceType = (int)dataSourceLink.DataSourceProvider.DataSourceType; + } + + public Guid DataSourceGuid { get; set; } + public string Name { get; set; } + public int DataSourceType { get; set; } +} + +internal class StrataSphereAdHocReportMeasure : IStrataSphereAdHocReportSectionItem +{ + public StrataSphereAdHocReportMeasure() + { + + } + + public StrataSphereAdHocReportMeasure(IAdHocReportSectionMeasure measure) + { + MeasureId = measure.MeasureID; + Index = measure.DisplayOrder; + Name = measure.Name; + DisplayFormat = measure.DisplayFormat; + ColumnWidth = measure.ColumnWidth; + } + + public string MeasureId { get; set; } + public string Name { get; set; } + public int Index { get; set; } + + public string DisplayFormat { get; set; } + public int ColumnWidth { get; set; } + + public bool IsOnChartXAxis { get; set; } + public bool IsOnChartYAxis { get; set; } + + // section level filters + public List Parameters { get; set; } = new List(); + + public List ConditionalFormats { get; set; } = new List(); +} + +internal class StrataSphereAdHocReportSection +{ + public StrataSphereAdHocReportSection() + { + + } + + public StrataSphereAdHocReportSection(IReportDataGenerationSection section) + { + Name = section.Name; + DisplayOrder = section.DisplayOrder; + IsOnColumn = section.IsOnColumn; + IsTimeRelative = section.IsTimeRelative; + IsFinancialReportSectionHidable = section.IsFinancialReportSectionHidable; + IsMergingRepeatHeader = section.IsMergingRepeatHeader; + IsSpaceAbove = section.IsSpaceAbove; + IsHidden = section.IsHidden; + DisplayLabel = section.DisplayText; + ShowSectionLabel = section.ShowSectionLabel; + ShowGrandTotal = section.ShowGrandTotal; + ShowMargin = section.ShowMargin; + } + + public string Name { get; set; } + public bool IsOnColumn { get; set; } + public int DisplayOrder { get; set; } + public bool IsTimeRelative { get; set; } + + public bool IsFinancialReportSectionHidable { get; set; } + public bool IsMergingRepeatHeader { get; set; } + public bool IsSpaceAbove { get; set; } + public bool IsHidden { get; set; } + + public string DisplayLabel { get; set; } + public bool ShowSectionLabel { get; set; } + public bool ShowGrandTotal { get; set; } + public bool IsAutoNameFilter { get; set; } + public bool ShowMargin { get; set; } + + public List Attributes { get; set; } = new List(); + + public List Measures { get; set; } = new List(); + + public List Calculations { get; set; } = new List(); +} + + + +internal class StrataSphereAdHocReportSetup +{ + public string Style { get; set; } + + public StrataSphereAdHocReportSortArgs SortArgs { get; set; } + + public List DataSources { get; set; } = new List(); + + public StrataSphereAdHocReportConfig ChartConfig { get; set; } = null; + + public List Sections { get; set; } = new List(); + + public List Parameters { get; set; } = new List(); + + public List ServiceLines { get; set; } = + new List(); + +} + +public class StrataSphereAdHocReportSortArgs +{ + public StrataSphereAdHocReportTupleInfo TupleInfo { get; set; } + public bool IsAscending { get; set; } + public int SortCount { get; set; } + public int Top { get; set; } + public bool IsTopPercent { get; set; } + public bool IsIncludeAllOthers { get; set; } + + public StrataSphereAdHocReportSortArgs() + { + TupleInfo = new StrataSphereAdHocReportTupleInfo(); + } + + public StrataSphereAdHocReportSortArgs(IReportDataGenerationSetup reportSetup) + : this() + { + if (reportSetup.SortArgs == null) return; + TupleInfo = new StrataSphereAdHocReportTupleInfo(reportSetup); + IsAscending = reportSetup.SortArgs.IsAscending; + SortCount = reportSetup.SortArgs.SortCount; + Top = reportSetup.SortArgs.Top; + IsTopPercent = reportSetup.SortArgs.IsTopPercent; + IsIncludeAllOthers = reportSetup.SortArgs.IsIncludeAllOthers; + } + + public static implicit operator ReportSortArgs(StrataSphereAdHocReportSortArgs sortArgs) + { + var result = sortArgs.TupleInfo != null + ? new ReportSortArgs(sortArgs.TupleInfo) + : new ReportSortArgs(); + result.IsAscending = sortArgs.IsAscending; + result.SortCount = sortArgs.SortCount; + result.Top = sortArgs.Top; + result.IsTopPercent = sortArgs.IsTopPercent; + result.IsIncludeAllOthers = sortArgs.IsIncludeAllOthers; + return result; + } +} + +public class StrataSphereAdHocReportTupleInfo +{ + public Dictionary PartialRowTuple { get; set; } + public Dictionary PartialColTuple { get; set; } + public string MainMeasureName { get; private set; } + public string RowMeasureName { get; set; } + public string ColMeasureName { get; set; } + public Guid ColMeasureGUID { get; set; } + public string FormatString { get; set; } + public int rowIndex { get; set; } + public int colIndex { get; set; } + public Guid ColumnSectionGUID { get; set; } + public IAdHocReportSectionMeasure MainMeasure { get; set; } + + public StrataSphereAdHocReportTupleInfo() + { + PartialRowTuple = new Dictionary(); + PartialColTuple = new Dictionary(); + ColumnSectionGUID = Guid.Empty; + ColMeasureGUID = Guid.Empty; + } + + private IAdHocReportSectionMeasure _mainMeasure; + protected virtual IAdHocReportSectionMeasure InMemoryMeasure + { + get + { + if (_mainMeasure != null) return _mainMeasure; + _mainMeasure = new InMemoryReportMeasure + { + ColumnName = string.IsNullOrEmpty(RowMeasureName) + ? RowMeasureName + : ColMeasureName + }; + return _mainMeasure; + } + } + + public StrataSphereAdHocReportTupleInfo(ReportTupleInfo tupleInfo) + : this() + { + if (tupleInfo == null) return; + tupleInfo.PartialRowTuple.Keys.ToList() + .ForEach(key => PartialRowTuple.Add(key, tupleInfo.PartialRowTuple[key])); + tupleInfo.PartialColTuple.Keys.ToList() + .ForEach(key => PartialColTuple.Add(key, tupleInfo.PartialColTuple[key])); + //MainMeasure = tupleInfo.MainMeasure; + MainMeasureName = tupleInfo.MainMeasureName; + RowMeasureName = tupleInfo.RowMeasureName; + ColMeasureName = tupleInfo.ColMeasureName; + ColMeasureGUID = tupleInfo.ColMeasureGUID; + FormatString = tupleInfo.FormatString; + rowIndex = tupleInfo.rowIndex; + colIndex = tupleInfo.colIndex; + ColumnSectionGUID = tupleInfo.ColumnSectionGUID; + } + + public StrataSphereAdHocReportTupleInfo(IReportDataGenerationSetup reportSetup) + : this(reportSetup.SortArgs.TupleInfo) + { + if (reportSetup.SortArgs.TupleInfo?.MainMeasure == null) return; + switch (reportSetup) + { + case DSCubeReportSetup cubeReportSetup: + MainMeasure = cubeReportSetup.SortArgs.TupleInfo.MainMeasure as DSCubeReportSectionMeasure; + break; + case ClientReportSetup clientReportSetup: + MainMeasure = clientReportSetup.SortArgs.TupleInfo.MainMeasure as ClientReportSectionMeasure; + break; + default: + MainMeasure = InMemoryMeasure; + break; + } + switch (MainMeasure) + { + case DSCubeReportSectionMeasure cubeMeasure: + cubeMeasure.Re + portSetup = null; + break; + case ClientReportSectionMeasure clientMeasure: + clientMeasure.ReportSetup = null; + break; + } + } + + public static implicit operator ReportTupleInfo(StrataSphereAdHocReportTupleInfo tupleInfo) + { + if (tupleInfo == null) return null; + var result = new ReportTupleInfo + { + PartialRowTuple = new Dictionary(), + PartialColTuple = new Dictionary(), + MainMeasure = tupleInfo.MainMeasure?.CopyMeasure(), + RowMeasureName = tupleInfo.RowMeasureName, + ColMeasureName = tupleInfo.ColMeasureName, + ColMeasureGUID = tupleInfo.ColMeasureGUID, + FormatString = tupleInfo.FormatString, + rowIndex = tupleInfo.rowIndex, + colIndex = tupleInfo.colIndex, + ColumnSectionGUID = tupleInfo.ColumnSectionGUID + }; + tupleInfo.PartialRowTuple.Keys.ToList() + .ForEach(key => result.PartialRowTuple.Add(key, tupleInfo.PartialRowTuple[key])); + tupleInfo.PartialColTuple.Keys.ToList() + .ForEach(key => result.PartialColTuple.Add(key, tupleInfo.PartialColTuple[key])); + return result; + } +} +#endregion + +#region Other Stuff + +public interface IReportDataGenerationSection : IStrataTreeNode +{ + bool IsDeleted { get; } + IReportDataGenerationSetup ReportSetup { get; } + ITGuid ReportSectionGUIDTyped { get; } + Guid SectionGUID { get; } + string Name { get; } + + bool IsOnColumn { get; } + int DisplayOrder { get; } + bool IsTimeRelative { get; } + + bool IsFinancialReportSectionHidable { get; } + bool IsMergingRepeatHeader { get; } + bool IsSpaceAbove { get; } + + void AddAttribute(IAdHocReportSectionAttribute attr); + bool RemoveAttribute(IAdHocReportSectionAttribute attr); + void RemoveAttributeAt(int attrIndex); + + void AddMeasure(IAdHocReportSectionMeasure meas); + bool RemoveMeasure(IAdHocReportSectionMeasure meas); + void RemoveMeasureAt(int attrIndex); + + void AddCalculation(IAdHocReportSectionCalculation calc); + bool RemoveCalculation(IAdHocReportSectionCalculation calc); + void RemoveCalculationAt(int calcIndex); + + IEnumerable Calculations { get; } + IEnumerable Attributes { get; } + IEnumerable Measures { get; } + + IEnumerable GetAdditionalSelectColumns(); + + IEnumerable GetCostMeasureFilter(); + + IList GetValidVisibleAttributes(bool isDrillDown); + void RefreshVisibilityStatuses(IAdHocReportSectionAttribute drilledAttr, eReportDrilldownStatus ddStatus); + + List ChildMeasuresAndCalcs { get; } + List VisibleMeasuresAndCalcs { get; } + IAdHocReportSectionMeasure GetPrimaryMeasureForUseInCalculation(); + + List GetAllSectionItems { get; } + IEnumerable GetExtractAttributes(); + List GetAllSectionItemGUIDs(); + + bool HasParameters(); + void RefreshDrilldownStatuses(); + + void HidePartiallyVisibleItems(); + + #region " Rendering " + + bool IsHidden { get; } + bool ShowSectionLabel { get; } + + bool ShowGrandTotal { get; set; } + string GrandTotalDisplayTextOverride { get; } + string GrandTotalDisplayFormatOverride { get; } + bool ShowMargin { get; } + + string SectionLabelCSSClassName { get; } + + #endregion +} + +public class ReportTupleInfo +{ + public ReportTupleInfo() + { + this.PartialRowTuple = new Dictionary(); + this.PartialColTuple = new Dictionary(); + } + + [NonSerialized] + private IReportTupleFactory _TupleFactory; + public IReportTupleFactory TupleFactory + { + get { return _TupleFactory; } + set { _TupleFactory = value; } + } + + private Dictionary _Tuple; + public Dictionary Tuple + { + get + { + if (_Tuple == null) + { + RefreshTuple(); + } + return _Tuple; + } + set { _Tuple = value; } + } + + [DataMember] + public Dictionary PartialRowTuple { get; set; } + + [DataMember] + public Dictionary PartialColTuple { get; set; } + + [DataMember] + public string MainMeasureName { get; private set; } + + private IAdHocReportSectionMeasure _MainMeasure; + public IAdHocReportSectionMeasure MainMeasure + { + get { return _MainMeasure; } + set + { + _MainMeasure = value; + MainMeasureName = (value == null) ? string.Empty : value.ColumnName; + } + } + + [DataMember] + public string RowMeasureName { get; set; } + + [DataMember] + public string ColMeasureName { get; set; } + + [DataMember] + public Guid ColMeasureGUID { get; set; } + + [DataMember] + public string FormatString { get; set; } + + [DataMember] + public int rowIndex { get; set; } + + [DataMember] + public int colIndex { get; set; } + + [DataMember] + public Guid ColumnSectionGUID { get; set; } + + public Dictionary RefreshTuple() + { + _Tuple = new Dictionary(); + if (PartialRowTuple != null) + { + _Tuple.MergeUnsafe(PartialRowTuple); + } + if (PartialColTuple != null) + { + _Tuple.Merge(PartialColTuple); + } + return _Tuple; + } + + public ReportTupleInfo MakeCopy() + { + var copy = new ReportTupleInfo() + { + TupleFactory = this.TupleFactory, + PartialColTuple = new Dictionary(this.PartialColTuple), + PartialRowTuple = new Dictionary(this.PartialRowTuple), + MainMeasure = this.MainMeasure, + RowMeasureName = this.RowMeasureName, + ColMeasureName = this.ColMeasureName, + ColMeasureGUID = this.ColMeasureGUID, + ColumnSectionGUID = this.ColumnSectionGUID, + FormatString = this.FormatString, + rowIndex = this.rowIndex, + colIndex = this.colIndex + }; + return copy; + } + + public void MergeTuples(ReportTupleInfo tupleToMerge) + { + PartialColTuple = (Dictionary)PartialColTuple.MergeCopy(tupleToMerge.PartialColTuple); + PartialRowTuple = (Dictionary)PartialRowTuple.MergeCopy(tupleToMerge.PartialRowTuple); + RefreshTuple(); + } + + public override bool Equals(object obj) + { + if (!(obj is ReportTupleInfo)) + { + return false; + } + + var y = (ReportTupleInfo)obj; + + if (this.MainMeasure == null) + { + return false; + } + + if (!this.MainMeasure.ID.Equals(y.MainMeasure.ID)) + { + return false; + } + if (!this.Tuple.ValueEquals(y.Tuple)) + { + return false; + } + + return true; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + //not sure how else we can do GetHashCode without being super slow so we will need the base class decide + } +} + +public interface IAdHocReportSectionAttribute : IAdHocReportSectionItem +{ + ITGuid AttributeGUIDTyped { get; } + string DimensionID { get; } + string AttributeID { get; } + bool ShowSubtotal { get; set; } + + SortOrder SortOrder { get; } + eClientReportVisibilityStatus VisibilityStatus { get; set; } + eReportDrilldownStatus DrilldownStatus { get; set; } + + string FilterMemberCSV { get; set; } + List FilterMembers { get; set; } + List FilterMembersVisible { get; } +} + +public interface IAdHocReportSectionItem //: IDisplayOrder, IStrataTreeNode +{ + Guid ReportSectionGUID { get; } + Guid ReportSectionItemGUID { get; } + + string Name { get; set; } + string ColumnName { get; } + bool IsHidden { get; } + bool IsDeleted { get; } + + eClientReportSectionItemType ItemType { get; } + void SetID(Guid newGUID); + + int ColumnWidth { get; set; } + string DetailReportGUIDsCSV { get; } + Guid BeforeCopyGUID { get; set; } +} + +public interface ITGuid +{ + Guid Value { get; set; } + bool IsEmpty { get; set; } +} + +public enum eClientReportSectionItemType +{ + Attribute = 0, + Hierarchy = 1, + Measure = 2, + Calculation = 3 +} + +public enum eReportDrilldownStatus +{ + None = 0, + Drilldown = 1, + Drillup = 2 +} + +public enum eClientReportVisibilityStatus +{ + Hidden = 0, + CompletelyVisible = 1, + PartiallyVisible = 2 +} + +#endregion \ No newline at end of file diff --git a/StarterSet API/Starter Set API with Flurl test.linq b/StarterSet API/Starter Set API with Flurl test.linq new file mode 100644 index 0000000..5c0cef4 --- /dev/null +++ b/StarterSet API/Starter Set API with Flurl test.linq @@ -0,0 +1,107 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Flurl + Flurl.Http + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Flurl + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Threading.Tasks + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + Flurl.Http + + +private string baseUrl; + +void Main() +{ + baseUrl = "https://api-dev.sdt.local/StrataSphere.Web.API.Service//api/v1/"; + GetDefinitions().Dump(); + GetDefinitionsAsync().Dump(); +} + +// Define other methods and classes here +public async Task> GetDefinitionsAsync() +{ + return await GetTAsync("Definitions"); +} + +public async Task> GetTAsync(string pathSegment) +{ + var flurlRequest = baseUrl.AppendPathSegment(pathSegment).GetJsonAsync>(); + //flurlRequest.Wait(); + await flurlRequest; + while (!flurlRequest.IsCompleted) + { + if (flurlRequest.Exception != null) return new List(); + } + var result = flurlRequest.Result; + return result; +} + +public IEnumerable GetDefinitions() +{ + return Task.Run(async () => GetDefinitionsAsync().Result).Result; +} + +public class DefinitionDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public Guid DimensionGuid { get; set; } + public Guid AttributeGuid { get; set; } + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + +} + + diff --git a/StarterSet API/Starter Set Client StandardDefinitions.linq b/StarterSet API/Starter Set Client StandardDefinitions.linq new file mode 100644 index 0000000..8a93c36 --- /dev/null +++ b/StarterSet API/Starter Set Client StandardDefinitions.linq @@ -0,0 +1,72 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +Definitions +.OrderBy(d => d.ObjectType) +.ThenBy(d => d.Name) +.Dump(); \ No newline at end of file diff --git a/StarterSet API/Starter Set Missing Report Card Items for DatabaseGuid.linq b/StarterSet API/Starter Set Missing Report Card Items for DatabaseGuid.linq new file mode 100644 index 0000000..14b86b7 --- /dev/null +++ b/StarterSet API/Starter Set Missing Report Card Items for DatabaseGuid.linq @@ -0,0 +1,66 @@ + + + 463c2997-8a6a-4688-9575-6549e5215f7b + true + D0011-SQL-01.sdt.local + StrataSphere + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +from ri in ReportItems +join rci in ReportCardItems on ri.ReportCardItemId equals rci.Id +orderby ri.ReportId, rci.ReportCardItemType, rci.Name +where (!(from rcm in ReportCardMatches where rcm.ReportCardItemId == ri.ReportCardItemId && rcm.DatabaseGuid == Guid.Parse("9BC301F9-66C3-48AA-81E7-114F88A449EA") select rcm).Any()) +select new { ri.ReportId, rci.Id, rci.Name, rci.ReportCardItemType, rci.ReportType, rci.ReportCardItemDataJson } diff --git a/StarterSet API/Starter Set Test.linq b/StarterSet API/Starter Set Test.linq new file mode 100644 index 0000000..f063eba --- /dev/null +++ b/StarterSet API/Starter Set Test.linq @@ -0,0 +1,176 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + System.Dynamic + + +private string BaseUrl = "https://api-prod.sdt.local/StrataSphere.Web.API.Service/api/v1/"; + +void Main() +{ + RestClient client = new RestClient(); + var reports = GetList(client, "Reports"); + var setups = reports.ToList() + .Select(rpt => GetList(client, $"Reports\\{rpt.Id}\\Setup")); + var attributes = setups.SelectMany(s => (s.Sections as List).Select(x => (x.Attributes as List))); + //attributes.Dump(); + var results = attributes + .SelectMany(a => a.Select(x => new AttributeInfo + { + DimensionId = x.DimensionId, + AttributeId = x.AttributeId, + Name = x.Name, + Parameters = (x.Parameters as List) + .ConvertAll(p => new AttributeInfo + { + DimensionId = p.DimensionId, + AttributeId = p.AttributeId, + MeasureId = p.MeasureId, + DisplayOrder = p.DisplayOrder, + Name = p.Name + }).OrderBy(p => p.DisplayOrder) + })).GroupBy(x => x.ToString(), (grp, data) => data.First()) + .OrderBy(a => a.Name); + results.Dump(); +} + +public class AttributeInfo +{ + public string DimensionId { get; set; } + public string AttributeId { get; set; } + public string MeasureId { get; set; } + public long DisplayOrder { get; set; } = 0; + public string Name { get; set; } + public IEnumerable Parameters { get; set; } + + public override bool Equals(object obj) + { + var test = obj as AttributeInfo; + if (test == null) return false; + return test.Name == Name && test.DimensionId == DimensionId && test.AttributeId == AttributeId; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override string ToString() + { + return $"{Name} {DimensionId} {AttributeId} {DisplayOrder} {(Parameters?.Aggregate("", (x, y) => $"{x} {y.ToString()}") ?? "")}"; + } +} + +dynamic GetList(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + var converter = new ExpandoObjectConverter(); + return JsonConvert.DeserializeObject(client.Execute(request).Content, converter); +} + +IEnumerable GetList(RestClient client, string something) +{ + return Get>(client, something); +} + +T Get(RestClient client, string something) +{ + client.BaseUrl = new Uri(BaseUrl + something); + RestRequest request = new RestRequest(); + request.Method = Method.GET; + return JsonConvert.DeserializeObject(client.Execute(request).Content); +} + +public enum eStrataSphereItemCategory +{ + Report, + Dashboard +} + +public enum StrataSphereReportEnum +{ + Report, + DSCubeReport, + SQLReport, + ClientReport +} + +public class ReportDto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public eStrataSphereItemCategory Category => eStrataSphereItemCategory.Report; + public string Tagline => + $"Report | {Module} | {DateCreated.ToString("MMM-dd-YYYY")} | {DownloadCount} downloads"; + + public StrataSphereReportEnum ReportType { get; set; } + public string Module { get; set; } + public string MinJazzVersion { get; set; } + public string MaxJazzVersion { get; set; } + public string ReportSetupJson { get; set; } + public List DefinitionIds { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateLastModified { get; set; } + public int DownloadCount { get; set; } + + public ReportDto() + { + ReportSetupJson = "{}"; + DefinitionIds = new List(); + } +} diff --git a/StarterSet API/StarterSet DB Compare.linq b/StarterSet API/StarterSet DB Compare.linq new file mode 100644 index 0000000..6bb23d0 --- /dev/null +++ b/StarterSet API/StarterSet DB Compare.linq @@ -0,0 +1,239 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private string tableQuery = @"SELECT c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE +, CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey +FROM INFORMATION_SCHEMA.COLUMNS AS c +LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON tc.TABLE_SCHEMA = c.TABLE_SCHEMA AND tc.TABLE_NAME = c.TABLE_NAME +LEFT OUTER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.TABLE_SCHEMA = tc.TABLE_SCHEMA AND ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME AND ccu.COLUMN_NAME = c.COLUMN_NAME +WHERE c.TABLE_SCHEMA in ('stratasphere') +AND (CASE c.TABLE_SCHEMA +WHEN 'stratasphere' THEN 1 +ELSE + CASE WHEN c.TABLE_NAME IN ('DimCaseType', 'CaseTypeFamily', 'CaseTypeFamilyMapping', 'CaseTypeFamilyMappingAPRDRG', 'CaseTypeFamilyMappingICD10', 'CaseTypeFamilyMappingCPT', 'CaseTypeFamilyVersion') + THEN 1 ELSE 0 END END = 1) +AND c.DATA_TYPE NOT IN ('datetime','uniqueidentifier', 'timestamp') +AND NOT (c.COLUMN_NAME = 'RowID' and CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) = 1) +AND tc.CONSTRAINT_TYPE = 'Primary Key' +ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION"; + +private List OrderByStatements; +private List ColumnsToBeExcluded; + +void Main() +{ + OrderByStatements = new List + { + new OrderByInformation{ + TableName = "cci.InitiativeWorkflowHistory", + OrderBy = "\r\nOrder By OBJ.FromStep, OBJ.ToStep" + }, + new OrderByInformation{ + TableName = "cci.VariationEncounterSavingInfo", + OrderBy = "\r\nOrder By OBJ.EncounterRecordNumber, OBJ.PhysicianID" + }, + new OrderByInformation{ + TableName = "stratasphere.MDXScoreToCube", + OrderBy = "\r\nOrder By OBJ.OrgPin, OBJ.ScoreDimensionName, ScoreHierarchyName" + } + }; + ColumnsToBeExcluded = new List { + new ColumnsToExclude{ + TableName = "stratasphere.MDXScoreToCube", + ColumnNames = new [] {"DateCreated", "DateLastModified"} + } + }; + var conn = new Tuple("D0011-SQL-01.sdt.local", "stratasphere"); + var q = GetQueries(conn); + + var connections = new ServerInstance[] { + new ServerInstance("D0011-SQL-01.sdt.local","stratasphere", q.Select(r => r.TableName).ToArray()), + new ServerInstance("E0001-SQL-11.sdt.local", "stratasphere", q.Select(r => r.TableName).ToArray() ) + }.ToList(); + var sql = string.Join("\r\n", q.Select(r => r.SqlSelect)); + var dataLegacy = GetData(connections[0], sql); + var dataUpdate = GetData(connections[1], sql); + + foreach (var dt in Enumerable.Range(0, dataLegacy.Tables.Count)) + { + var legacy = dataLegacy.Tables[dt].Rows; + var update = dataUpdate.Tables[dt].Rows; + var idxCount = legacy.Count; + var compare = new List>(); + foreach (var row in Enumerable.Range(0, idxCount)) + { + var r = legacy[row]; + if (row < update.Count) + { + var u = update[row]; + var rJson = JsonConvert.SerializeObject(r.ItemArray); + var uJson = JsonConvert.SerializeObject(u.ItemArray); + if (rJson != uJson) + { + compare.Add(new Tuple(r, u)); + } + } + else + { + compare.Add(new Tuple(r, null)); + } + } + if (compare.Any()) + { + compare.Dump(dataLegacy.Tables[dt].TableName, 2); + } + else + { + "No differences found in data".Dump(dataLegacy.Tables[dt].TableName); + } + } +} + +// Define other methods and classes here + +public class ServerInstance +{ + public string Server { get; set; } + public string Database { get; set; } + public IEnumerable TableNames { get; set; } + public ServerInstance(string server, string database, string[] tableNames) + { + Server = server; + Database = database; + TableNames = tableNames; + } +} + +public class OrderByInformation +{ + public string TableName { get; set; } + public string OrderBy { get; set; } +} + +public class ColumnsToExclude +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } +} + +public List GetQueries(Tuple connection) +{ + var server = connection.Item1; + var database = connection.Item2; + var sql = tableQuery; + var connStr = $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;"; + using (var conn = new SqlConnection(connStr)) + { + var dataset = new DataTable(); + var adapter = new SqlDataAdapter(sql, conn); + adapter.Fill(dataset); + var items = dataset.AsEnumerable().Select(r => r).ToList().ConvertAll(r => r.ItemArray) + .Select(r => new InformationSchema { schema = (string)r[0], table = (string)r[1], column = (string)r[2], datatype = (string)r[3], isPrimaryKey = (bool)r[4] }) + .Where(r => !ColumnsToBeExcluded.SingleOrDefault(ctbe => ctbe.TableName == r.schemaTable)?.ColumnNames.Contains(r.column) ?? true) + .GroupBy(r => new { r.schema, r.table }, (t, c) => + new SqlInformation + { + TableName = $"{t.schema}.{t.table}", + SqlSelect = "Select\r\n" + c.Aggregate("", (x, y) => $"{x}, obj.{y.column}\r\n").Substring(1) + $" FROM {t.schema}.{t.table} OBJ" + + OrderByStatements.SingleOrDefault(obs => obs.TableName.Equals($"{t.schema}.{t.table}", StringComparison.CurrentCultureIgnoreCase))?.OrderBy ?? "" + + ";" + }) + .ToList(); + return items; + } +} + +public class SqlInformation +{ + public string TableName { get; set; } + public string SqlSelect { get; set; } +} + +public class InformationSchema +{ + public string schema { get; set; } + public string table { get; set; } + public string column { get; set; } + public string datatype { get; set; } + public bool isPrimaryKey { get; set; } + public string schemaTable => $"{schema}.{table}"; +} + +public DataSet GetData(ServerInstance serverInstance, string sql) +{ + var server = serverInstance.Server; + var database = serverInstance.Database; + var connStr = $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;"; + using (var conn = new SqlConnection(connStr)) + { + var dataset = new DataSet(); + var adapter = new SqlDataAdapter(sql, conn); + adapter.Fill(dataset); + var tableNames = serverInstance.TableNames; + var idx = 0; + foreach (var tableName in tableNames) + { + dataset.Tables[idx].TableName = tableName; + idx += 1; + } + return dataset; + } +} \ No newline at end of file diff --git a/StarterSet DB compare.linq b/StarterSet DB compare.linq new file mode 100644 index 0000000..6476985 --- /dev/null +++ b/StarterSet DB compare.linq @@ -0,0 +1,505 @@ + + + 690bdbda-0918-4699-b08c-addb41e49702 + true + E0001-sql-11.sdt.local + StrataSphere + true + + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Linq.Dynamic + + +// This link provides a good explanation of the Dynamic Query used in the DataTableJoins +// https://ecs.syr.edu/faculty/fawcett/handouts/CoreTechnologies/CSharp/samples/CSharpSamples/LinqSamples/DynamicQuery/Dynamic%20Expressions.html +// + +private List SchemasAndTablesToReview = new List(); + +#region Options + +public static int TopRows = 2000; //int.MaxValue; +public static bool ShowTableQuery = false; +public static bool ShowTableList = false; +public static int TableDumpDepth = int.MaxValue; //2; + +#endregion + +void Main() +{ + SchemasAndTablesToReview.AddRange(new[] + { + new TablesAndColumns("stratasphere", null), + }); + + var tables = GetTables().ToList(); + // Using 'D|' at the beginning of a column name implies that the sort order is descending for that column + tables.ForEach(table => + { + switch (table.TableName) + { + case "Dashboard": + table.Init( + new[] { new OrderBy("Name"), new OrderBy("Module"), new OrderBy("MinJazzVersion") }, + new[] { "Id", "DateCreated", "DateLastModified" }, + new[] { "Name", "Module", "MinJazzVersion" } + ); + break; + case "DashboardCardItem": + table.Init( + new[] { new OrderBy("Name") }, + new[] { "ItemId", "DateCreated", "DateLastModified" }, + new[] { "Name", "DashboardCardItemType" } + ); + break; + case "Definition": + table.Init( + new[] { new OrderBy("Name"), new OrderBy("DimensionId"), new OrderBy("AttributeId") }, + new[] { "Id", "DateCreated", "DateLastModified" }, + new[] { "Name", "DimensionId", "AttributeId" } + ); + break; + case "Download": + table.Init( + new[] { new OrderBy("UserName"), new OrderBy("DownloadType") }, + new[] { "DownloadDateTime" }, + new[] { "UserName", "DownloadType" }, + null, + "OBJ.UserName <> 'System'" + ); + break; + case "MDXScoreToCube": + table.Init( + new[] { new OrderBy("OrgPin"), new OrderBy("ScoreDimensionName"), new OrderBy("ScoreHierarchyName") }, + new[] { "DateCreated", "DateLastModified" }, + new[] { "OrgPin", "ScoreDimensionName", "ScoreHierarchyName" } + ); + break; + case "Parameter": + table.Init( + new[] { new OrderBy("Name"), new OrderBy("ParameterType"), new OrderBy("DisplayOrder"), new OrderBy("DimensionName"), new OrderBy("AttributeName") }, + new[] { "DateCreated", "DateLastModified" }, + new[] { "Name", "ParameterType", "DimensionName", "AttributeName" }, + new[] { "ParameterJson" } + ); + break; + case "Report": + table.Init( + new[] { new OrderBy("Name"), new OrderBy("Module"), new OrderBy("MinJazzVersion") }, + new[] { "ItemId", "DownloadCount", "DateCreated", "DateLastModified" }, + new[] { "Name", "Module", "MinJazzVersion", "ReportType" }, + new[] { "ReportSetupJson" } + ); + break; + }; + }); + if (ShowTableList) tables.Dump(nameof(tables)); + var connections = new Connections + { + Legacy = new ServerInstance("E0001-SQL-11.sdt.local", "StrataSphere"), + Update = new ServerInstance("D0011-SQL-01.sdt.local", "StrataSphere") + // Legacy = new ServerInstance("D0011-SQL-01.sdt.local", "jazz tst Southern Illinois 20190918.1"), + // Update = new ServerInstance("D0011-SQL-01.sdt.local", "jazz tst Southern Illinois 20200331.1") + // Legacy = new ServerInstance("D0001-SQL-11.sdt.local", "jazz tst master prod 20190708.1"), + // Update = new ServerInstance("D0001-SQL-11.sdt.local", "jazz tst master prod") + }; + DoTheComparisons(connections, tables); +} + +// Define other methods and classes here + +#region Gather Table Information + +public string GetTableQuery() +{ + var tableSchemas = string.Join(", ", SchemasAndTablesToReview.Select(sattr => $"'{sattr.SchemaName}'")); + var tableList = string.Join("\r\n", SchemasAndTablesToReview.ConvertAll(sattr => + { + if (sattr.TableNames?.Any(cn => cn == "*") ?? true) + { + return $"WHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' THEN 1"; + } + else + { + return $"WHEN c.TABLE_SCHEMA = '{sattr.SchemaName}' AND c.TABLE_NAME IN ({string.Join(", ", sattr.TableNames.Select(cn => $"'{cn}'"))}) THEN 1"; + } + })); + return $@"SELECT c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE +, CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey +FROM INFORMATION_SCHEMA.COLUMNS AS c +LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON tc.TABLE_SCHEMA = c.TABLE_SCHEMA AND tc.TABLE_NAME = c.TABLE_NAME +LEFT OUTER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.TABLE_SCHEMA = tc.TABLE_SCHEMA AND ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME AND ccu.COLUMN_NAME = c.COLUMN_NAME +WHERE c.TABLE_SCHEMA in ({tableSchemas}) +AND (CASE +{tableList} +ELSE 0 +END = 1) +AND c.DATA_TYPE NOT IN ('datetime','uniqueidentifier', 'timestamp') +AND NOT (c.COLUMN_NAME = 'RowID' and CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) = 1) +AND tc.CONSTRAINT_TYPE = 'Primary Key' +ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION"; +} + +public IList
GetTables() +{ + var tableQuery = GetTableQuery(); + if (ShowTableQuery) tableQuery.Dump(nameof(tableQuery)); + return ExecuteQueryDynamic(tableQuery) + .GroupBy(x => new { x.TABLE_SCHEMA, x.TABLE_NAME }, + (g, d) => new Table(g.TABLE_SCHEMA, g.TABLE_NAME, + d.Select(y => new Column(y.COLUMN_NAME, y.DATA_TYPE, y.IsPrimaryKey)).ToList())) + .ToList(); +} + +public class Table +{ + public string SchemaName { get; set; } + public string TableName { get; set; } + public IList Columns { get; set; } = new List(); + public IList OrderBy { get; set; } = new List(); + public IList Exclude { get; set; } = new List(); + public IList KeyColumn { get; set; } = new List(); + public IList Json { get; set; } = new List(); + public string Where { get; set; } = ""; + internal string SchemaTable => $"{SchemaName}.{TableName}"; + public string SqlSelect => $"select TOP({TopRows}) \r\n\t{SelectColumns}\r\nfrom {SchemaTable} OBJ{Where}{OrderByStatement}"; + internal string SelectColumns => !Columns?.Any() ?? true ? "*" : string.Join(",\r\n\t", Columns.Where(c => !Exclude.ToList().Contains(c.ColumnName)).Select(c => c.ColumnName)); + internal string OrderByStatement => !OrderBy?.Any() ?? true ? "" : "\r\nOrder By " + string.Join(", ", OrderBy.Select(ob => $"{ob.ColumnName}{(ob.IsDescending ? " DESC" : "")}")); + + public Table(string schemaName, string tableName) + { + SchemaName = schemaName; + TableName = tableName; + Columns = new List(); + OrderBy = new List(); + } + + public Table(string schemaName, string tableName, IEnumerable columns) + : this(schemaName, tableName) + { + Columns = columns.ToList(); + } + + public Table(string schemaName, string tableName, IEnumerable columns, IEnumerable orderBy) + : this(schemaName, tableName, columns) + { + OrderBy = orderBy.ToList(); + } + + /// + /// + /// + /// + /// Using 'D|' at the beginning of a column name implies that the sort order is descending for that column + /// + public void Init(IEnumerable orderBys, IEnumerable excludes = null, IEnumerable keyColumns = null, IEnumerable jsonColumns = null, string where = "") + { + if (orderBys != null) + OrderBys(orderBys); + if (excludes != null) + Excludes(excludes); + if (keyColumns != null) + KeyColumns(keyColumns); + if (jsonColumns != null) + JsonColumns(jsonColumns); + if (!string.IsNullOrEmpty(where)) + where = $"\r\nwhere {where}"; + } + + /// + /// Using 'D|' at the beginning of a column name implies that the sort order is descending for that column + /// + public void OrderBys(IEnumerable orderBys) + { + OrderBy.Clear(); + ((List)OrderBy).AddRange(orderBys.Where(o => Columns.Select(c => c.ColumnName).Contains(o.ColumnName, StringComparer.CurrentCultureIgnoreCase))); + } + + public void Excludes(IEnumerable excludes) + { + Exclude.Clear(); + ((List)Exclude).AddRange(excludes.Where(e => Columns.Select(c => c.ColumnName).Contains(e, StringComparer.CurrentCultureIgnoreCase))); + } + + public void KeyColumns(IEnumerable keyColumns) + { + KeyColumn.Clear(); + ((List)KeyColumn).AddRange(keyColumns.Where(kc => Columns.Select(c => c.ColumnName).Contains(kc, StringComparer.CurrentCultureIgnoreCase))); + } + + public void JsonColumns(IEnumerable jsonColumns) + { + Json.Clear(); + ((List)Json).AddRange(jsonColumns.Where(jc => Columns.Select(c => c.ColumnName).Contains(jc, StringComparer.CurrentCultureIgnoreCase))); + } +} + +public class Column +{ + public string ColumnName { get; set; } + public string DataType { get; set; } + public bool IsPrimaryKey { get; set; } + public Column(string columnName, string dataType = "", bool isPrimaryKey = false) + { + ColumnName = columnName; + DataType = dataType; + IsPrimaryKey = isPrimaryKey; + } +} + +public class OrderBy +{ + public string ColumnName { get; set; } + public bool IsDescending { get; set; } = false; + + public OrderBy(string columnName, bool isDescending = false) + { + ColumnName = columnName; + IsDescending = isDescending; + } + +} + +public class TablesAndColumns +{ + public string SchemaName { get; set; } + public IEnumerable TableNames { get; set; } + public TablesAndColumns(string schemaName, IEnumerable tables) + { + SchemaName = schemaName; + TableNames = tables; + } +} + +public class OrderByInformation +{ + public string TableName { get; set; } + public IEnumerable OrderBy { get; set; } + public OrderByInformation(string tableName, IEnumerable columns) + { + TableName = tableName; + OrderBy = columns + .Select(c => + new OrderBy(c.StartsWith("D|") ? c.Substring(2) : c, + c.StartsWith("D|"))); + } +} + +public class ColumnsToExclude +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public ColumnsToExclude(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +public class JsonColumns +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public JsonColumns(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +#endregion + +#region Do the comparisons + +public void DoTheComparisons(Connections connections, IEnumerable
tables) +{ + foreach (var table in tables) + { + var sql = table.SqlSelect; + var dataLegacy = GetData(connections.Legacy, sql, table.TableName); + var dataUpdate = GetData(connections.Update, sql, table.TableName); + + var compare = new List(); + var jsonColumns = table.Json.ToList() ?? null; + dataLegacy.AsEnumerable().ToList() + .ForEach(legacyRow => + { + DataRow updateRow = default(DataRow); + if (table.KeyColumn.Any()) + { + var keys = string.Join("|", table.KeyColumn.Select(kc => $"{legacyRow.Field(kc)}")); + updateRow = dataUpdate.AsEnumerable() + .FirstOrDefault(y => keys == string.Join("|", table.KeyColumn.Select(kc => $"{y.Field(kc)}"))); + } + if (updateRow == null || JsonConvert.SerializeObject(legacyRow.ItemArray) != JsonConvert.SerializeObject(updateRow.ItemArray)) + compare.Add(new CompareSet(compare.Count, legacyRow, updateRow, jsonColumns)); + }); + dataUpdate.AsEnumerable().ToList() + .ForEach(updateRow => + { + DataRow legacyRow = default(DataRow); + if (table.KeyColumn.Any()) + { + var keys = string.Join("|", table.KeyColumn.Select(kc => $"{updateRow.Field(kc)}")); + legacyRow = dataLegacy.AsEnumerable() + .FirstOrDefault(y => keys == string.Join("|", table.KeyColumn.Select(kc => $"{y.Field(kc)}"))); + } + if (legacyRow == null) + compare.Add(new CompareSet(compare.Count, legacyRow, updateRow, jsonColumns)); + }); + if (compare.Any()) + { + compare.OrderBy(c => c.OrderBy) + .Dump($"{table.SchemaTable} ( {compare.Count()} / {dataLegacy.Rows.Count} / {dataUpdate.Rows.Count} rows )", TableDumpDepth); + } + else + { + "No differences found in data".Dump($"{table.SchemaTable} ( 0 / {dataLegacy.Rows.Count} / {dataUpdate.Rows.Count} rows )"); + } + } +} + +public class Connections +{ + public ServerInstance Legacy { get; set; } + public ServerInstance Update { get; set; } +} + +public class ServerInstance +{ + public string Server { get; set; } + public string Database { get; set; } + + public ServerInstance(string server, string database) + { + Server = server; + Database = database; + } +} + +public DataTable GetData(ServerInstance serverInstance, string sql, string tableName) +{ + var server = serverInstance.Server; + var database = serverInstance.Database; + var connStr = $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;"; + using (var conn = new SqlConnection(connStr)) + { + var datatable = new DataTable(); + var adapter = new SqlDataAdapter(sql, conn); + try + { + adapter.Fill(datatable); + } + catch (Exception) + { + sql.Dump(nameof(sql)); + throw; + } + datatable.TableName = tableName; + return datatable; + } +} + +public class CompareSet +{ + internal int Row { get; set; } + internal IList ColumnNames { get; set; } + internal IList Legacy { get; set; } + internal IList Update { get; set; } + internal int OrderBy { get; set; } = 0; + public IList Rows { get; set; } + internal IList JsonColumns { get; set; } + public CompareSet(int row, DataRow right, DataRow left, IList jsonColumns) + { + Row = ++row; + if (right == null) + { + ColumnNames = left.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + } + else + { + ColumnNames = right.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + } + Legacy = right?.ItemArray.ToList(); + Update = left?.ItemArray.ToList(); + OrderBy = (right != null ? 0 : 2) + (left != null ? 0 : 1); + JsonColumns = jsonColumns; + Rows = ColumnNames.Select((c, i) => new Row(row, c, Legacy?[i], Update?[i], JsonColumns?.Contains(c, StringComparer.CurrentCultureIgnoreCase) ?? false)).ToList(); + } + + public CompareSet(int row, DataRow right, DataRow left) + : this(row, right, left, null) + { + } + + object ToDump() => new + { + Row = $"{Row}", + Rows = Rows.Select(x => new + { + Column = (x.Left ?? "").Equals(x.Right ?? "") ? (object)x.Column : new XElement("LINQPad.HTML", new XElement("div", new XAttribute("style", "background-color:lightyellow;color:black"), x.Column)), + Legacy = x.Left, + Update = x.Right + }) + }; + +} + +public class Row +{ + public int RowId { get; set; } + public string Column; + public bool IsJson; + public object Left; + public object Right; + + public Row(int row, string column, object left, object right) + { + RowId = row; + Column = column; + Left = left; + Right = right; + } + + public Row(int row, string column, object left, object right, bool isJson) + : this(row, column, left, right) + { + + IsJson = isJson; + if (!isJson) return; + if (left != null) + { + Left = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(left.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + } + if (right != null) + { + Right = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(right.ToString(), + new JsonSerializerSettings + { + Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) + { + args.ErrorContext.Handled = true; + } + }), Newtonsoft.Json.Formatting.Indented); + } + } + +} + +#endregion \ No newline at end of file diff --git a/StarterSet Validator Task Migration Issues.linq b/StarterSet Validator Task Migration Issues.linq new file mode 100644 index 0000000..e65d9ba --- /dev/null +++ b/StarterSet Validator Task Migration Issues.linq @@ -0,0 +1,65 @@ + + + 4f885e7e-d8bb-427c-a54e-8e3e1c3137a7 + true + IOAK-SQL-LOG-01.sdt.local + elog10 prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +(from log in ViewTaskEngineLogDetailed + where log.TaskName == "StarterSet Validator Task" + orderby log.TimeStamp descending + select new { log.TaskName, log.TaskEngineVersion, log.ServerName, log.DatabaseName, log.OrgPin, log.PhysicalName, log.Description}).Dump(); diff --git a/StrataJazz FileSize Report.linq b/StrataJazz FileSize Report.linq new file mode 100644 index 0000000..2a41c88 --- /dev/null +++ b/StrataJazz FileSize Report.linq @@ -0,0 +1,128 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var baseDir = @"D:\Git\Jazz"; + + var solution = Path.Combine(baseDir, "veracode.sln"); + var regex = new Regex(@"[^=]*=\s+""([^""]*)"",\s""([^""]*)"".*"); + var veracodeProjectFolders = File.ReadAllLines(solution) + .Where(l => l.StartsWith("Project(")) + .Where(l => regex.Match(l).Success) + .ToList(); + var fileTypes = new Regex(@"^\.vb$|^\.css?$|^\.jsx?$|^\.html$|^\.as[achmp]{1}x$|^\.xs[xd]{1}$"); + //veracodeProjectFolders.Dump(); + var vpnames = veracodeProjectFolders + .Where(l => !string.IsNullOrEmpty(regex.Replace(l, "$1"))) + .ToDictionary(l => regex.Replace(l, "$1"), l => Path.GetDirectoryName(Path.Combine(baseDir, regex.Replace(l, "$2")))); + var vpf = vpnames.Values.ToList(); + + //vpnames.Dump(); + //vpf.ConvertAll(v => Path.GetDirectoryName(Path.Combine(baseDir, v))).Dump(); + + baseDir = Path.Combine(baseDir, @"Code\"); + var dirs = Directory.EnumerateDirectories(baseDir) + .Where(d => vpf.Contains(d)) + .ToList() + .ConvertAll(d => d.Replace(baseDir, "")); + var fileSizes = new Dictionary>(); + var fileExtensions = new List(); + foreach (var dir in dirs) + { + var path = Path.Combine(baseDir, dir); + //$"{baseDir} + {dir} = {path}".Dump(); + foreach (var file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)) + { + if (file.Contains(@"\obj\") || file.Contains(@"\bin\")) continue; + var fi = new FileInfo(file); + fileExtensions.Add(fi.Extension); + if (!fileTypes.IsMatch(fi.Extension)) continue; + var fDir = fi.DirectoryName.Replace(baseDir, "").Split(Path.DirectorySeparatorChar)[0]; + var fSize = fi.Length; + if (!fileSizes.ContainsKey(dir)) + fileSizes.Add(dir, new Dictionary()); + if (!fileSizes[dir].ContainsKey(fi.Extension)) + fileSizes[dir].Add(fi.Extension, 0); + fileSizes[dir][fi.Extension] += fSize; + } + } + var report = fileSizes.Keys.ToList() + .ConvertAll(key => fileSizes[key].Keys.ToList() + .ConvertAll(ext => new DirectorySize { Directory = key, FileExtension = ext, fileSize = fileSizes[key][ext] })) + .SelectMany(x => x.Select(y => y)); + report.Sum(x => x.fileSize).BytesToString().Dump("Total Source"); + report.OrderBy(r => r.Directory).ThenBy(r => r.FileExtension).Dump(); + fileExtensions.Distinct().OrderBy(e => e).Dump(); +} + +// Define other methods and classes here + +public class DirectorySize +{ + public string Directory { get; set; } + public string FileExtension { get; set; } + public long fileSize { get; set; } + object ToDump() => new + { + Directory, + FileExtension, + FileSize = new XElement("LINQPad.HTML", + new XElement("div", + new XAttribute("align", "right"), + new XAttribute("style", $"background-color:{((fileSize > Math.Pow(1024, 3)) ? "red" : (fileSize > Math.Pow(1024, 2)) ? "violet" : "white")};"), + $"{fileSize.BytesToString()}".PadLeft(10))), + }; + +} \ No newline at end of file diff --git a/Testing the IsFileInDirectory function.linq b/Testing the IsFileInDirectory function.linq new file mode 100644 index 0000000..1a88cc6 --- /dev/null +++ b/Testing the IsFileInDirectory function.linq @@ -0,0 +1,87 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +Sub Main + Dim aListOfDirectories = New List(Of String) + aListOfDirectories.Add("d:\Git") + 'This file does not exist + IsFileInDirectory("D:\Git\thom.txt", aListOfDirectories).Dump("D:\Git\thom.txt") + MyIsFileInDirectory("D:\Git\thom.txt", aListOfDirectories).Dump("D:\Git\thom.txt") + 'This file does exist + IsFileInDirectory("D:\Git\new migration.txt", aListOfDirectories).Dump("D:\Git\new migration.txt") + MyIsFileInDirectory("D:\Git\new migration.txt", aListOfDirectories).Dump("D:\Git\new migration.txt") + MyIsFileInDirectory("D:\Git\new migration.txt", aListOfDirectories).Equals(IsFileInDirectory("D:\Git\new migration.txt", aListOfDirectories)).Dump("My Equals not My") +End Sub + +' Define other methods and classes here +Public Shared Function MyIsFileInDirectory(ByVal aFilePath As String, ByVal aListOfDirectories As List(Of String)) As Boolean + Dim fileObject = New System.IO.FileInfo(aFilePath) + If Not fileObject.Exists + Return False + End If + Return aListOfDirectories _ + .Select(Function(allowedDir) New System.IO.DirectoryInfo(allowedDir)) _ + .Any(Function(testDirectory) fileObject.Directory.FullName.Equals(testDirectory.FullName.TrimEnd("\"), StringComparison.OrdinalIgnoreCase)) +End Function + +Public Shared Function IsFileInDirectory(ByVal aFilePath As String, ByVal aListOfDirectories As List(Of String)) As Boolean + Dim fileObject = New System.IO.FileInfo(aFilePath) + For Each allowedDir In aListOfDirectories + Dim testDirectory = New System.IO.DirectoryInfo(allowedDir) + If fileObject.Directory.FullName.Equals(testDirectory.FullName, StringComparison.OrdinalIgnoreCase) Then + Return True + End If + Next + Return False +End Function \ No newline at end of file diff --git a/TimeZones.linq b/TimeZones.linq new file mode 100644 index 0000000..fdc7c15 --- /dev/null +++ b/TimeZones.linq @@ -0,0 +1,76 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + TimeZoneNames + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.Globalization + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + TimeZoneNames + + +TimeZoneInfo.GetSystemTimeZones().Dump(); +TimeZoneInfo.GetSystemTimeZones() + .SelectMany(tzi => new [] { + TZNames.GetAbbreviationsForTimeZone(tzi.Id, "en-US").Daylight != TZNames.GetAbbreviationsForTimeZone(tzi.Id, "en-US").Standard + ? new { Key = tzi.Id.Replace("Standard", "Daylight"), Value = TZNames.GetAbbreviationsForTimeZone(tzi.Id, "en-US").Daylight } + : new { Key = tzi.Id, Value = TZNames.GetAbbreviationsForTimeZone(tzi.Id, "en-US").Daylight }, + new { Key = tzi.Id, Value = TZNames.GetAbbreviationsForTimeZone(tzi.Id, "en-US").Standard }}) + .GroupBy(x => x.Key) + .Select(g => g.First()) + .ToDictionary(item => item.Key, item => item.Value) + .OrderBy(item => item.Key) + .Dump(); \ No newline at end of file diff --git a/UV CaseTypeConfig Parsing.linq b/UV CaseTypeConfig Parsing.linq new file mode 100644 index 0000000..7195ecc --- /dev/null +++ b/UV CaseTypeConfig Parsing.linq @@ -0,0 +1,95 @@ + + Newtonsoft.Json + + + +void Main() +{ +var CaseTypConfigJSON = @"{""SOIROMInclusions"":[{""SOI"":""1"",""ROM"":""1""},{""SOI"":""1"",""ROM"":""2""},{""SOI"":""1"",""ROM"":""3""},{""SOI"":""1"",""ROM"":""4""},{""SOI"":""2"",""ROM"":""1""},{""SOI"":""2"",""ROM"":""2""},{""SOI"":""2"",""ROM"":""3""},{""SOI"":""2"",""ROM"":""4""},{""SOI"":""3"",""ROM"":""1""},{""SOI"":""3"",""ROM"":""2""},{""SOI"":""3"",""ROM"":""3""},{""SOI"":""3"",""ROM"":""4""},{""SOI"":""4"",""ROM"":""1""},{""SOI"":""4"",""ROM"":""2""},{""SOI"":""4"",""ROM"":""3""},{""SOI"":""4"",""ROM"":""4""}],""AgeCohortIDInclusions"":[5,6,7,8,9,10,3,4],""PhysicianIDExclusions"":[],""StandardDeviationExcludedTypeEnum"":0,""LengthOfStayThreshold"":0,""CPTCodes"":[],""PatientTypeRollupIDInclusions"":[3,2,1],""PhysicianMinVolume"":0}"; +JsonConvert.DeserializeObject(CaseTypConfigJSON).Dump(); +} + +// Define other methods and classes here + +public enum StandardDeviationExclusions +{ + None = 0, + TwoStdDev = 1, + ThreeStdDev = 2, + CustomLOSOutlier = 3 +} + +[Serializable] +public class CaseTypeConfiguration //: ICaseTypeConfiguration +{ + public int PhysicianMinVolume { get; set; } = 0; +} + +public class DRGCaseTypeConfiguration : CaseTypeConfiguration//, IDRGCaseTypeConfiguration +{ + // ReSharper disable once InconsistentNaming + public List AgeCohortIDInclusions { get; set; } = new List(); + public List PhysicianIDExclusions { get; set; } = new List(); + public StandardDeviationExclusions StandardDeviationExcludedTypeEnum { get; set; } = StandardDeviationExclusions.None; + public int LengthOfStayThreshold { get; set; } = 0; + public HashSet CPTCodes { get; set; } = new HashSet(); + public List PatientTypeRollupIDInclusions { get; set; } = new List(); +} + +[Serializable] +public class SOIROMInclusion : IEquatable +{ + + public string SOI { get; set; } + public string ROM { get; set; } + + public SOIROMInclusion() + { + + } + + public SOIROMInclusion(string soi, string rom) + { + SOI = soi; + ROM = rom; + } + + public SOIROMInclusion(int soi, int rom) + { + SOI = soi.ToString(); + ROM = rom.ToString(); + } + + public bool Equals(SOIROMInclusion other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(ROM, other.ROM, StringComparison.OrdinalIgnoreCase) && + string.Equals(SOI, other.SOI, StringComparison.OrdinalIgnoreCase); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((SOIROMInclusion)obj); + } + + public override int GetHashCode() + { + unchecked + { + return ((ROM != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(ROM) : 0) * 397) ^ + (SOI != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(SOI) : 0); + } + } + +} + +public class APRDRGCaseTypeConfiguration : DRGCaseTypeConfiguration +{ + // ReSharper disable once InconsistentNaming + public List SOIROMInclusions { get; set; } = new List(); + +} diff --git a/UV Export Analysis.linq b/UV Export Analysis.linq new file mode 100644 index 0000000..a8b34e8 --- /dev/null +++ b/UV Export Analysis.linq @@ -0,0 +1,122 @@ + + LinqToCsv + LINQtoCSV + + +void Main() +{ + var path = @"D:\Users\tlamb\Downloads"; + var utilizationFile = @"CI_Sepsis LOS - Pharmacy_All Physicians_Utilization_01-15-2021.csv"; + //@"CI_Sepsis LOS - Pharmacy_All Physicians_Utilization_01-14-2021.csv"; + var trackingDetailsFile = @"CI_Sepsis LOS - Pharmacy_01-14-2021 Tracking Details.csv"; + + var inputFileDescription = new CsvFileDescription + { + SeparatorChar = ',', + FirstLineHasColumnNames = true + }; + + var cc = new CsvContext(); + + var trackingDetails = cc.Read(Path.Combine(path, trackingDetailsFile), inputFileDescription) + .GroupBy(td => td.Charge_Description, (g, d) => new Consolidated + { + Charge_Code = g, + TotalDirectVariableCost = d.Sum(u => u.TotalDirectVariableCost) + }) + .OrderBy(td => td.Charge_Code); + + var utilization = cc.Read(Path.Combine(path, utilizationFile), inputFileDescription) + .GroupBy(u => u.Charge_Code, (g, d) => d.Select(u => new Consolidated + { + Charge_Code = u.Charge_Code, + Baseline_TotalDirectVariableCost = u.Baseline_TotalDirectVariableCost, + Tracking_TotalDirectVariableCost = u.Tracking_TotalDirectVariableCost + })) + .SelectMany(u => u) + .OrderBy(u => u.Charge_Code); + + var consolidated = from td in utilization + join u in trackingDetails on td.Charge_Code equals u.Charge_Code into g + from x in g.DefaultIfEmpty() + select new Consolidated + { + Charge_Code = x?.Charge_Code ?? td.Charge_Code, + TotalDirectVariableCost = x?.TotalDirectVariableCost ?? 0.0d, + Baseline_TotalDirectVariableCost = td?.Baseline_TotalDirectVariableCost ?? 0.0d, + Tracking_TotalDirectVariableCost = td?.Tracking_TotalDirectVariableCost ?? 0.0d + }; + cc.Write(consolidated, Path.Combine(path, "consolidated.csv"), inputFileDescription); +} + +// Define other methods and classes here +public class TrackingDetails +{ + public string Encounter { get; set; } + public DateTime Admit_Date { get; set; } + public DateTime Discharge_Date { get; set; } + public string Physician { get; set; } + public string Physician_Group { get; set; } + public DateTime Date_of_Service { get; set; } + public string Rollup { get; set; } + public string Charge_Description { get; set; } + public int UOS { get; set; } + public string Unit_Direct_Variable_Cost { get; set; } + public string Total_Direct_Variable_Cost { get; set; } + public double TotalDirectVariableCost + { + get + { + return double.TryParse(Total_Direct_Variable_Cost.Replace("$", "").Replace("(", "-").Replace(")", ""), out var result) ? result : 0.0d; + } + } +} + +public class Utilization +{ + public string Rollup { get; set; } + public string Charge_Code { get; set; } + public string Direct_Variable_Cost { get; set; } + public string x { get; set; } + public string Cases1 { get; set; } + public string Quantity1 { get; set; } + public string Pct_of_Total_Cases1 { get; set; } + public string Qty_Used_Cases1 { get; set; } + public string Cases2 { get; set; } + public string Quantity2 { get; set; } + public string Pct_of_Total_Cases2 { get; set; } + public string Qty_Used_Cases2 { get; set; } + public string Pct_of_Total_Cases3 { get; set; } + public string Qty_Used_Cases3 { get; set; } + public string b { get; set; } + public string CostPerCase1 { get; set; } + public string CostPerCase2 { get; set; } + public string CostPerCase3 { get; set; } + public string Total_Direct_Variable_Cost1 { get; set; } + public string Total_Direct_Variable_Cost2 { get; set; } + public string Total_Direct_Variable_Cost3 { get; set; } + public double Baseline_TotalDirectVariableCost + { + get + { + return string.IsNullOrEmpty(Total_Direct_Variable_Cost1) ? 0.0d + : double.TryParse(Total_Direct_Variable_Cost1.Replace("$-", "0").Replace("$", "").Replace("(", "-").Replace(")", ""), out var result) ? result : 0.0d; + } + } + public double Tracking_TotalDirectVariableCost + { + get + { + return string.IsNullOrEmpty(Total_Direct_Variable_Cost2) ? 0.0d + : double.TryParse(Total_Direct_Variable_Cost2.Replace("$-", "0").Replace("$", "").Replace("(", "-").Replace(")", ""), out var result) ? result : 0.0d; + } + } +} + +public class Consolidated +{ + public string Charge_Code { get; set; } + public double TotalDirectVariableCost { get; set; } + public double Baseline_TotalDirectVariableCost { get; set; } + public double Tracking_TotalDirectVariableCost { get; set; } +} \ No newline at end of file diff --git a/Understanding UNC PayPeriods.linq b/Understanding UNC PayPeriods.linq new file mode 100644 index 0000000..940b657 --- /dev/null +++ b/Understanding UNC PayPeriods.linq @@ -0,0 +1,193 @@ + + + 40766b24-ff74-431b-b387-6c221ede77cf + true + p3121-sql-02.sdt.local + jazz prd UNC 20180206.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var validPayPeriods = PayPeriodCycles + .GroupBy(g => new { g.PayCycleID, g.PayCycleName }, (g, pp) => + new + { + g.PayCycleID, + g.PayCycleName, + PayPeriods = pp.Select(p => + new payperiodtiming + { + PayPeriodID = p.PayPeriodID, + PeriodEndCalendarDate = p.PeriodEndCalendarDate, + PeriodStartCalendarDate = p.PeriodStartCalendarDate + }).OrderByDescending(p => p.PeriodEndCalendarDate).Take(6) + }) + .SelectMany(g => g.PayPeriods); + + DeptPayPeriods + .ToList() + // .OrderBy(dpp => dpp.DepartmentID) + // .ThenByDescending(dpp => dpp.PayPeriodID) + .GroupBy(dpp => new { dpp.DepartmentID, dpp.Department }, (g, dpp) => new deptpayperiodtiming + { + DepartmentID = g.DepartmentID, + Department = g.Department, + PayPeriodTimings = dpp.Select(d => d.PayPeriodID).Distinct() + .Join(validPayPeriods, x => x, vpp => vpp.PayPeriodID, (x, vpp) => vpp) + .OrderByDescending(d => d.PayPeriodID) + }) + .Where(dpp => dpp.PayPeriodTimings.Any()) + .Dump("Department PayPeriods"); +} + +public void ShowCycles() +{ + PayPeriodCycles + .GroupBy(g => new { g.PayCycleID, g.PayCycleName }, (g, pp) => + new + { + g.PayCycleID, + g.PayCycleName, + PayPeriods = pp.Select(p => + new payperiodtiming + { + PayPeriodID = p.PayPeriodID, + PeriodEndCalendarDate = p.PeriodEndCalendarDate, + PeriodStartCalendarDate = p.PeriodStartCalendarDate + }).OrderByDescending(p => p.PeriodEndCalendarDate).Take(6) + }) + .Dump("Pay Period Cycles"); +} + +public IEnumerable DeptPayPeriods => (from fact in FactPayrollSampledPayPeriods + join dept in DimDepartments on fact.DepartmentID equals dept.DepartmentID + select new deptpayperiod + { + PayPeriodID = fact.PayPeriodID, + DepartmentID = fact.DepartmentID, + Department = dept.Name + }).Union((from fact in ViewPrimaryStatisticsStaffingByPayPeriod + join dept in DimDepartments on fact.DepartmentID equals dept.DepartmentID + select new deptpayperiod + { + PayPeriodID = fact.PayPeriodID, + DepartmentID = fact.DepartmentID, + Department = dept.Name + })).Distinct(); + +public IEnumerable PayPeriodCycles => from pp in DimPayPeriods + where pp.PeriodEndCalendarDate < DateTime.Now + select new payperiodcycle + { + PayPeriodID = pp.PayPeriodID, + PayCycleID = pp.PayCycleID, + PayCycleName = pp.PayCycleName, + PeriodEndCalendarDate = pp.PeriodEndCalendarDate, + PeriodStartCalendarDate = pp.PeriodStartCalendarDate + }; + +// Define other methods and classes here + +public class deptpayperiod +{ + public short PayPeriodID { get; set; } + public int DepartmentID { get; set; } + public string Department { get; set; } +} + +public class deptpayperiodtiming +{ + public int DepartmentID { get; set; } + public string Department { get; set; } + internal IEnumerable PayPeriodTimings { get; set; } + public IDictionary PayPeriods => + PayPeriodTimings.ToDictionary(ppt => ppt.PayPeriodID, + ppt => new payperioddate + { + PeriodStartCalendarDate = ppt.PeriodStartCalendarDate, + PeriodEndCalendarDate = ppt.PeriodEndCalendarDate + }); + public DateTime? PeriodStartDate => PayPeriodTimings.OrderByDescending(ppt => ppt.PayPeriodID).First().PeriodStartCalendarDate; + public DateTime? PeriodEndDate => PayPeriodTimings.OrderByDescending(ppt => ppt.PayPeriodID).First().PeriodEndCalendarDate; +} + +public class payperioddate +{ + public DateTime PeriodEndCalendarDate { get; set; } + public DateTime? PeriodStartCalendarDate { get; set; } + object ToDump() => new + { + PeriodStartDate = $"{PeriodStartCalendarDate:yyyy MM dd}", + PeriodEndDate = $"{PeriodEndCalendarDate:yyyy MM dd}" + }; +} + +public class payperiodtiming : payperioddate +{ + public short PayPeriodID { get; set; } + object ToDump() => new + { + PayPeriodID = $"{PayPeriodID}", + PeriodStartDate = $"{PeriodStartCalendarDate:yyyy MM dd}", + PeriodEndDate = $"{PeriodEndCalendarDate:yyyy MM dd}" + }; +} + +public class payperiodcycle : payperiodtiming +{ + public int PayCycleID { get; set; } + public string PayCycleName { get; set; } +} \ No newline at end of file diff --git a/Update StrataSphere Reports DefinitionsJson.linq b/Update StrataSphere Reports DefinitionsJson.linq new file mode 100644 index 0000000..be24fb5 --- /dev/null +++ b/Update StrataSphere Reports DefinitionsJson.linq @@ -0,0 +1,88 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +//var reportList = Reports.ToList(); +var reports = Reports.ToList() +.Where(rpt => !string.IsNullOrEmpty(rpt.ReportSetupJson) && rpt.ReportSetupJson.StartsWith("{") && rpt.ReportSetupJson.EndsWith("}")) +.Select(rpt => new { rpt, reportSetup = JObject.Parse(rpt.ReportSetupJson)}) +.ToList(); +//reports.Dump(); +//reports.ForEach(rpt => rpt.reportSetup.Dump()); + +var definitions = reports +.Select(rpt => new { rpt.rpt, definitions = rpt.reportSetup.SelectTokens("..StandardDefinitionGUID") +.Where(x => x.Value() != Guid.Empty.ToString()) +.Select(x => x.Value()).ToList()}) +.ToList(); +foreach(var def in definitions.Where(def => def.definitions.Count() > 0)) +{ + var defJson = JsonConvert.SerializeObject(def.definitions); + defJson.Dump(); + def.rpt.DefinitionsJson = defJson; + SubmitChanges(); +} diff --git a/Update TEScheduleTask for Starter Set Report Card Validator.linq b/Update TEScheduleTask for Starter Set Report Card Validator.linq new file mode 100644 index 0000000..7d50b48 --- /dev/null +++ b/Update TEScheduleTask for Starter Set Report Card Validator.linq @@ -0,0 +1,280 @@ + + + 4f885e7e-d8bb-427c-a54e-8e3e1c3137a7 + true + IOAK-SQL-LOG-01.sdt.local + jazz log prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.Dynamic + System.IO.Compression + System.Threading.Tasks + System.Data.Common + + +#region *** Enumerations *** + +public enum QueryRegions +{ + Production, + Training, + Oak, + Dev +} + +#endregion + +#region *** Options *** + +public static QueryRegions queryRegion = QueryRegions.Production; +public static int timeoutInMinutes = 2; + +#endregion + +#region *** Database Selection *** + +public static string[] appVersions = { // This is a list of appVersions to filter for in the database list +}; +public static string[] serverExclusions = { // This is a list of servers to exclude from the database list + @"paonsql19.sdt.local\instance1", + @"paonsql17.sdt.local\instance1", + @"p0555-sql-01.sdt.local\instance1", + "P0000-sql-01.sdt.local", + "P9900-SQL-03.sdt.local", + "P9900-sql-05.sdt.local" +}; +public static string[] dbExclusions = { // This is a list of database physical names to exclude from the database list +}; +public static string[] targetOrgPins = { // This is a list of org pins to target in the database list +}; +public static string[] targetServers = { // This is a list of servers to target in the database list +}; +public static string[] targetDBs = { // This is a list of database physicial names to target in the database list +}; + +#endregion *** Options *** + +#region *** SMC Settings and queries *** + +public static string smcSql => @"SELECT di.ServerName, di.DatabaseGUID, di.DatabaseName, di.PhysicalName, di.OrgPin, di.AppVersion, di.Description +FROM [dbo].[viewDatabaseInfo] di +WHERE 1=1" ++ (queryRegion == QueryRegions.Dev +? @" + AND di.PhysicalName like 'jazz%'" +: $@" + AND di.PhysicalName like 'jazz {(queryRegion != QueryRegions.Production ? "tst" : "prd")}%' + AND di.ServerName like 'p%'"); +public static string smcServer { get; set; } +public static string smcDB { get; set; } + +#endregion + +#region *** Program variables and settings *** + +public static IOrderedEnumerable databases => GetDatabases(); + +#endregion + +void Main() +{ + //databases.OrderBy(d => d.Server).ThenBy(d => d.PhysicalName).Dump($"{queryRegion} {nameof(databases)}"); + var workList = databases.OrderBy(d => d.Server).ThenBy(d => d.PhysicalName).ToList(); + var sqlQuery = @"select Name, t.Time, RepeatType, IsDisabled, HasRun, LastSubmittedDate, LastRunDate from TEScheduledTask t where name = 'Starter Set Report Card Validator'"; + var start = new DateTime(2020, 3, 23, 3, 0, 0); + var interval = 3; // minutes + workList.ForEach(db => + { + try + { + var connectionString = BuildConnectionString(db.Server, db.PhysicalName); + var database = new Database(); + var results = SelectDynamic(database, connectionString, sqlQuery); + if (results.Any()) + { + //var updateStatement = $@"Update TEScheduledTask set Time = '{start.ToString("hh:mm:ss tt")}' where name = 'Starter Set Report Card Validator'"; + //ExecuteCommand(database, connectionString, updateStatement); + //var after = SelectDynamic(database, connectionString, sqlQuery); + new + { + connectionString, + //updateStatement, + results//, + //after + }.Dump(); + + start = start.AddMinutes(interval); + } + } + catch (SqlException sqlEx) + { + sqlEx.Dump(); + return; + } + }); +} + +public class Database +{ + public string Server { get; set; } + public Guid DatabaseGuid { get; set; } + public string DatabaseName { get; set; } + public string PhysicalName { get; set; } + public string OrgPin { get; set; } + public string AppVersion { get; set; } + public string Description { get; set; } + public Dictionary Fields { get; set; } + + public Database() + { + + } + + public Database(DataRow dr) + { + Server = dr.Field("ServerName"); + DatabaseGuid = dr.Field("DatabaseGuid"); + DatabaseName = dr.Field("DatabaseName"); + PhysicalName = dr.Field("PhysicalName"); + OrgPin = dr.Field("OrgPin"); + AppVersion = dr.Field("AppVersion"); + Description = dr.Field("Description"); + Fields = new Dictionary(); + foreach (DataColumn column in dr.Table.Columns) + { + var index = dr.Table.Columns.IndexOf(column); + Fields.Add(column.ColumnName, dr[index].ToString()); + } + } + + object ToDump() => (object)new + { + Server, + DatabaseGuid, + DatabaseName, + PhysicalName, + OrgPin, + AppVersion, + Description + }; +} + +public static IOrderedEnumerable GetDatabases() +{ + switch (queryRegion) + { + case QueryRegions.Production: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc prod"; + break; + case QueryRegions.Training: + smcServer = "ioak-sql-smc-01"; + smcDB = "smc training"; + break; + case QueryRegions.Oak: + smcServer = "ioak-sql-smc-01.sdt.local"; + smcDB = "smc qa"; + break; + default: + smcServer = "DDEN-SQL-SMC-01.sdt.local"; + smcDB = "smc dev"; + break; + } + List databases = new List(); + var connStr = BuildConnectionString(smcServer, smcDB); + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(smcSql, conn); + command.CommandType = CommandType.Text; + var database = new DataSet(); + conn.Open(); + using (DbDataReader reader = command.ExecuteReader()) + { + while (true) + { + var table = new DataTable(); + database.Tables.Add(table); + table.Load(reader); + if (reader.IsClosed || !reader.NextResult()) break; + } + } + conn.Close(); + databases = database.Tables[0].AsEnumerable().Select(dr => new Database(dr)).ToList(); + databases = databases.Where(dr => !dbExclusions.Contains(dr.PhysicalName) && !serverExclusions.Contains(dr.Server)).ToList(); + if (targetOrgPins.Any()) + databases = databases.Where(dr => targetOrgPins.Contains(dr.OrgPin)).ToList(); + if (targetServers.Any()) + databases = databases.Where(dr => targetServers.Contains(dr.Server)).ToList(); + if (targetDBs.Any()) + databases = databases.Where(dr => targetDBs.Contains(dr.PhysicalName)).ToList(); + if (appVersions.Any()) + databases = databases.Where(dr => appVersions.Contains(dr.AppVersion)).ToList(); + } + return databases + .OrderBy(d => d.Server).ThenBy(d => d.PhysicalName); +} + +public static void ExecuteCommand(Database db, string connStr, string sql) +{ + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(sql, conn); + command.CommandType = CommandType.Text; + command.CommandTimeout = (int)TimeSpan.FromMinutes(timeoutInMinutes).TotalSeconds; + conn.Open(); + try + { + command.ExecuteNonQuery(); + conn.Close(); + } + catch (SqlException sqlEx) + { + sqlEx.Dump(); + } + } +} + +public static IEnumerable SelectDynamic(Database db, string connStr, string sql) +{ + using (var conn = new SqlConnection(connStr)) + { + var command = new SqlCommand(sql, conn); + command.CommandType = CommandType.Text; + command.CommandTimeout = (int)TimeSpan.FromMinutes(timeoutInMinutes).TotalSeconds; + var database = new DataSet(); + conn.Open(); + using (DbDataReader reader = command.ExecuteReader()) + { + while (true) + { + var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList(); + foreach (IDataRecord record in reader as IEnumerable) + { + var expando = new ExpandoObject() as IDictionary; + foreach (var name in names) + expando[name] = record[name]; + + yield return expando; + } + if (reader.IsClosed || !reader.NextResult()) break; + } + } + conn.Close(); + } +} + +public static string BuildConnectionString(string server, string database, string username = null, string password = null) +{ + return username == null + ? $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;" + : $"data source={server};initial catalog='{database}';User ID={username};pwd={password}"; +} diff --git a/User Role Department PayPeriod query.linq b/User Role Department PayPeriod query.linq new file mode 100644 index 0000000..5f9054d --- /dev/null +++ b/User Role Department PayPeriod query.linq @@ -0,0 +1,241 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +/* +(from roleDetail in ViewS3RoleAssignmentDetail +where roleDetail.RoleName.StartsWith("MR ") +&& roleDetail.LootID.Contains("MRDEPT|") +select roleDetail.RoleName) +.Distinct() +.OrderBy(p => p).ToList() +.Aggregate("var roles = new [] { ", (x, y) => x + $"\"{y}\", ").TrimEnd(", ".ToCharArray()) + " }" +*/ +void Main() +{ + var userNames = new List{ + "dachee" + }; + // var userGUIDs = from up in UserProfiles + // where userNames.Contains(up.UserName) + // select up.UserGUID; + // new List{ + // //new Guid("0e8a4d58-f9c1-4a49-837c-dd7db45793fe") + // new Guid("76CD86B8-D769-4AAE-9083-F8E6D005AA9D") + // }; + var users = (from user in UserProfiles + select new User + { + UserInfo = new UserInfo + { + UserGUID = user.UserGUID, + UserName = user.UserName, + NameFirst = user.NameFirst, + NameLast = user.NameLast, + EmailAddress = user.EmailAddress + } + }) + .Where(u => userNames.Contains(u.UserInfo.UserName)) + .ToList(); + var roles = new[] { +// "MR - Commenter", + "MR - Director", + "MR - Exec Director AVP", + "MR - Executive", +// "MR - Finance", + "MR - Manager", +// "MR - Read Only", +// "MR - Read Write Only", + "MR - Vice President" + }; + users + .ForEach(u => + { + int x; + u.Roles = (from roleDetail in ViewS3RoleAssignmentDetail + where roleDetail.UserGUID == u.UserInfo.UserGUID + select roleDetail.RoleName).Distinct().OrderBy(r => r).ToList(); + u.DepartmentIDs = (from roleDetail in ViewS3RoleAssignmentDetail + where roleDetail.UserGUID == u.UserInfo.UserGUID + && roleDetail.LootID.Contains("MRDEPT|") + && roles.Contains(roleDetail.RoleName) + select new { depts = roleDetail.LootID.Split('|').ToList() }) + .ToList().SelectMany(d => d.depts).Where(d => int.TryParse(d, out x)).ToList().ConvertAll(int.Parse).Distinct() + .ToList(); + u.DeptPayPeriods = (from fact in FactDepartmentProductivityMetrics + join pp in DimPayPeriods on fact.PayPeriodID equals pp.PayPeriodID + where u.DepartmentIDs.Contains(fact.DepartmentID) + && pp.PeriodEndCalendarDate < new DateTime(2019, 6, 17) + && pp.PeriodStartCalendarDate.HasValue + orderby pp.PeriodStartCalendarDate descending + select new { fact.DepartmentID, pp.PayPeriodID, PeriodStartCalendarDate = pp.PeriodStartCalendarDate.Value, pp.PeriodEndCalendarDate }) + .Distinct().ToList() + .GroupBy(dpp => dpp.DepartmentID, (key, grp) => new DeptPayPeriods + { + DepartmentID = key, + PayPeriods = grp.Select(g => new PayPeriod + { + PeriodID = g.PayPeriodID, + StartDate = g.PeriodStartCalendarDate, + EndDate = g.PeriodEndCalendarDate + }) + .ToList().OrderByDescending(pp => pp.StartDate).Take(6).ToList() + }).ToList(); + var payperiodIDs = u.DeptPayPeriods.SelectMany(d => d.PayPeriods.Select(pp => pp.PeriodID)); + var hours = from fact in FactPayrollSampledPayPeriods + join payperiod in DimPayPeriods on fact.PayPeriodID equals payperiod.PayPeriodID + join paycode in DimPayCodeGroups on fact.PayCodeGroupID equals paycode.PayCodeGroupID + join prodclass in DimProductiveClasses on paycode.ProductiveClassID equals prodclass.ProductiveClassID + join department in DimDepartments on fact.DepartmentID equals department.DepartmentID + where new[] { 1, 4 }.Contains(fact.TimeClassID) + && prodclass.Name == "Productive" + && u.DepartmentIDs.Contains(fact.DepartmentID) + && payperiodIDs.Contains(fact.PayPeriodID) + select new DeptPayPeriodTime(fact.DepartmentID, fact.PayPeriodID, fact.TimeClassID, fact.Hours, "hours"); + var dollars = from fact in FactPayrollSampledPayPeriods + join payperiod in DimPayPeriods on fact.PayPeriodID equals payperiod.PayPeriodID + join paycode in DimPayCodeGroups on fact.PayCodeGroupID equals paycode.PayCodeGroupID + //join prodclass in DimProductiveClasses on paycode.ProductiveClassID equals prodclass.ProductiveClassID + join department in DimDepartments on fact.DepartmentID equals department.DepartmentID + where new[] { 1, 4 }.Contains(fact.TimeClassID) + //&& prodclass.Name == "Productive" + && u.DepartmentIDs.Contains(fact.DepartmentID) + && payperiodIDs.Contains(fact.PayPeriodID) + select new DeptPayPeriodTime(fact.DepartmentID, fact.PayPeriodID, fact.TimeClassID, fact.Dollars, "dollars"); + var uos = from fact in ViewPrimaryStatisticsStaffingByPayPeriod + join payperiod in DimPayPeriods on fact.PayPeriodID equals payperiod.PayPeriodID + //join paycode in DimPayCodeGroups on fact.PayCodeGroupID equals paycode.PayCodeGroupID + //join prodclass in DimProductiveClasses on paycode.ProductiveClassID equals prodclass.ProductiveClassID + join department in DimDepartments on fact.DepartmentID equals department.DepartmentID + where new[] { 1, 4 }.Contains(fact.TimeClassID) + //&& prodclass.Name == "Productive" + && u.DepartmentIDs.Contains(fact.DepartmentID) + && payperiodIDs.Contains(fact.PayPeriodID) + select new DeptPayPeriodTime(fact.DepartmentID, fact.PayPeriodID, fact.TimeClassID, fact.Units.HasValue ? fact.Units.Value : 0.0m, "uos"); + var unitSummary = hours.ToList().Concat(dollars.ToList()).Concat(uos.ToList()) + .GroupBy(dppt => new { dppt.DepartmentID, dppt.PeriodID, dppt.TimeClassID, dppt.UnitType }, + (key, grp) => new DeptPayPeriodTime(key.DepartmentID, key.PeriodID, key.TimeClassID, + grp.Where(pp => u.DeptPeriodDict[pp.DepartmentID].Contains(pp.PeriodID)).Sum(i => i.Units), key.UnitType)) + .Where(item => u.DeptPeriodDict[item.DepartmentID].Contains(item.PeriodID)) + .OrderBy(item => item.DepartmentID) + .ThenByDescending(item => item.PeriodID).ToList(); + u.Units = unitSummary; + }); + users.Dump("Users"); + users//.Where(u => userGUIDs.Contains(u.UserInfo.UserGUID)) + .Aggregate("", (x, y) => x + y.DepartmentIDs.Aggregate(", ", (a, b) => $"{a}, {b}")).Substring(2) + .Dump(); + users//.Where(u => userGUIDs.Contains(u.UserInfo.UserGUID)) + .Aggregate("", (x, y) => x + y.DeptPayPeriods.SelectMany(dpp => dpp.PayPeriods.Select(pp => pp.PeriodID)).Distinct() + .Aggregate(", ", (a, b) => $"{a}, {b}")).Substring(2) + .Dump(); +} + +// Define other methods and classes here +public class User +{ + public UserInfo UserInfo { get; set; } + public List Roles { get; set; } + public List DepartmentIDs { get; set; } + public List DeptPayPeriods { get; set; } + internal Dictionary> DeptPeriodDict => + DeptPayPeriods.ToDictionary(dpp => dpp.DepartmentID, dpp => dpp.PayPeriods.Select(pp => pp.PeriodID).ToList()); + public List Units { get; set; } +} + +public class UserInfo +{ + public Guid UserGUID { get; set; } + public string UserName { get; set; } + public string NameFirst { get; set; } + public string NameLast { get; set; } + public string EmailAddress { get; set; } +} + +public class DeptPayPeriods +{ + public int DepartmentID { get; set; } + public List PayPeriods { get; set; } + //public List Units { get; set; } +} + +public class PayPeriod +{ + public short PeriodID { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } +} + +public class DeptPayPeriodTime +{ + public int DepartmentID { get; set; } + public short PeriodID { get; set; } + public byte TimeClassID { get; set; } + public decimal Units { get; set; } + public string UnitType { get; set; } + public DeptPayPeriodTime(int departmentID, short periodID, byte timeClassID, decimal units, string unitType) + { + DepartmentID = departmentID; + PeriodID = periodID; + TimeClassID = timeClassID; + Units = units; + UnitType = unitType; + } +} \ No newline at end of file diff --git a/UserRole query.linq b/UserRole query.linq new file mode 100644 index 0000000..b3dffb6 --- /dev/null +++ b/UserRole query.linq @@ -0,0 +1,71 @@ + + + 40766b24-ff74-431b-b387-6c221ede77cf + true + p3121-sql-02.sdt.local + jazz prd UNC 20180206.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + +(from role in UserRoles +where role.Category == "MR" +select role).Dump(); + +} + +// Define other methods and classes here diff --git a/Validate Include and Exclude Regex's.linq b/Validate Include and Exclude Regex's.linq new file mode 100644 index 0000000..6a0f8af --- /dev/null +++ b/Validate Include and Exclude Regex's.linq @@ -0,0 +1,96 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var testset = new string[] { "3", "167", "168", "172", "4", "5", "6" }; + + var IncludeSolution = ""; + var ExcludeSolution = ""; + foreach (var check in checkInclude(IncludeSolution, testset)) + { + Console.WriteLine($"{check.Item1} is {check.Item2}"); + } + Console.WriteLine("\r\nExclude \"\""); + foreach (var check in checkExclude(ExcludeSolution, testset)) + { + Console.WriteLine($"{check.Item1} is {check.Item2}"); + } + Console.WriteLine("\r\nInclude \"^3$\""); + IncludeSolution = "^3$"; + foreach (var check in checkInclude(IncludeSolution, testset)) + { + Console.WriteLine($"{check.Item1} is {check.Item2}"); + } + ExcludeSolution = "^167$|^168$"; + Console.WriteLine("\r\nExclude \"^167$|^168$\""); + foreach (var check in checkExclude(ExcludeSolution, testset)) + { + Console.WriteLine($"{check.Item1} is {check.Item2}"); + } +} + +public IEnumerable> checkInclude(string pattern, string[] testset) +{ + var regex = string.IsNullOrEmpty(pattern) ? new Regex("^.+$") : new Regex(pattern); + return testset.ToList().ConvertAll(t => new Tuple(t, regex.IsMatch(t))); +} + +public IEnumerable> checkExclude(string pattern, string[] testset) +{ + var regex = string.IsNullOrEmpty(pattern) ? new Regex("^$") : new Regex(pattern); + return testset.ToList().ConvertAll(t => new Tuple(t, regex.IsMatch(t))); +} + +// Define other methods and classes here diff --git a/Veracode/Veracode CWE Analytics.linq b/Veracode/Veracode CWE Analytics.linq new file mode 100644 index 0000000..6950c09 --- /dev/null +++ b/Veracode/Veracode CWE Analytics.linq @@ -0,0 +1,387 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private XDocument xmlDoc = XDocument.Load(@"C:\Users\tlamb\Downloads\detailedreport_Strata_Jazz_Web_Jazz_web_201911511115217.xml"); + +void Main() +{ + //xmlDoc.DumpFormatted(); + var cwes = ParseVeracodeReport(xmlDoc).Where(cwe => cwe.count > 0); + var flaws = (from cwe in xmlDoc.Descendants() + where cwe.Name.LocalName == "cwe" + && cwe.Attributes().Any(a => a.Name == "cweid") + orderby Int32.Parse(cwe.Attribute("cweid").Value) + select cwe.Descendants().Where(c => c.Name.LocalName == "flaw")); + flaws + .SelectMany(f => f.Select(x => new Flaw(x))) + .Where(x => new[] { 4, 5 }.Contains(x.severity) && !x.hasMitigations && x.remediation_status == "New") + .OrderByDescending(x => x.severity) + .ThenBy(x => x.categoryid) + .ThenBy(x => x.cweid) + .ThenBy(x => x.issueid).Dump(); + //DumpTop20(cwes); + // DumpSummary(cwes); + // DumpModules(cwes); + // DumpByCweID(cwes); +} + +void DumpTop20(IEnumerable cwes) +{ + cwes.Where(cwe => cwe.count > 1 && new[] { 78, 15, 89 }.Contains(cwe.id)) + .Select(cwe => new { cwe.severity, cwe.category, cwe.details }) + .OrderByDescending(cwe => cwe.severity) + .Dump($"Top 20: ({cwes.Where(cwe => cwe.count > 1).Count()})"); +} + +void DumpSummary(IEnumerable cwes) +{ + cwes.Where(cwe => cwe.count > 1) + .OrderByDescending(cwe => cwe.severity).ThenByDescending(cwe => cwe.count) + .Dump($"Summary: ({cwes.Where(cwe => cwe.count > 1).Count()})"); + +} + +void DumpModules(IEnumerable cwes) +{ + var regex = new Regex(@"\.Test\.|\.IntegrationTests\.|\.UnitTests\."); + var modules = from m in xmlDoc.Descendants() + where m.Name.LocalName == "module" && m.Parent.Name.LocalName == "modules" + select new Module(m, cwes); + modules.Where(m => !regex.IsMatch(m.name) && m.totalNumberOfFlaws > 0) + .OrderBy(m => m.score).ThenByDescending(m => m.numberOfImportantFlaws) + .Dump($"Modules: ({modules.Count(m => !regex.IsMatch(m.name) && m.totalNumberOfFlaws > 0)})"); +} + +void DumpByCweID(IEnumerable cwes) +{ + cwes.Where(cwe => cwe.count > 1) + .OrderBy(cwe => cwe.id).ToList() + .ForEach(cwe => cwe.details.Dump($"ID: {cwe.id} {cwe.name} ({cwe.count})")); + //JsonConvert.SerializeObject(cwes, Newtonsoft.Json.Formatting.Indented).Dump("Json"); +} + +internal IEnumerable ParseVeracodeReport(XDocument xmlDoc) +{ + return from module in xmlDoc.Descendants() + where module.Name.LocalName == "cwe" + && module.Attributes().Any(a => a.Name == "cweid") + orderby Int32.Parse(module.Attribute("cweid").Value) + select new Cwe(module); +} + +public static class IntExtensions +{ + public static string SeverityLabel(this int severity) + { + switch (severity) + { + case 5: return "Very High"; + case 4: return "High"; + case 3: return "Medium"; + case 2: return "Low"; + case 1: return "Very Low"; + default: return "Informational"; + } + } + public static string CategoryLabel(this int category) + { + switch (category) + { + case 18: return "OS Command Injection"; + case 19: return "SQL Injections"; + case 24: return "Untrusted Initialization"; + case 21: return "CRLF Injection"; + case 10: return "Credentials Management"; + default: return $"{category}"; + } + } +} + +internal class Module +{ + public string name { get; set; } + public int score { get; set; } + public int totalNumberOfFlaws => flawsBySeverity.Values.Sum(); + public int numberOfImportantFlaws => flawsBySeverity.Where(f => f.Key > 2).Select(f => f.Value).Sum(); + private Dictionary flawsBySeverity { get; set; } + + public string flawsSummaryInfo => totalNumberOfFlaws > 0 + ? flawsBySeverity.Where(f => f.Value > 0).OrderByDescending(f => f.Key).Aggregate(new StringBuilder("Severity\n"), (x, y) => + x.Append($"{y.Key.SeverityLabel()}: {y.Value}\r\n")).ToString().TrimEnd(new[] { '\r', '\n' }) + : ""; + + public List summary => totalNumberOfFlaws > 0 + ? flawsBySeverity.Where(f => f.Value > 0) + .OrderByDescending(f => f.Key) + .Select(y => new Severity + { + severity = y.Key, + Count = y.Value + }).ToList() + : new List(); + + public string flawListInfo => !flaws.Any() + ? "" : flaws.Aggregate(new StringBuilder("path\tfile\tline\ttype\n"), (x, y) => + x.AppendLine($"{(string.IsNullOrEmpty(y.source.sourcefile) ? "na" : Path.GetDirectoryName(y.source.sourcefile))}\t" + + $"{(string.IsNullOrEmpty(y.source.sourcefile) ? "na" : Path.GetFileName(y.source.sourcefile))}\t{y.source.line}\t{y.source.type}")).ToString(); + + public List flawList => !flaws.Any() ? null : flaws + .ConvertAll(y => (ModuleFlaw)y.source); + + private List flaws { get; set; } + + public Module(XElement module, IEnumerable cwes) + { + name = module.Attribute("name")?.Value; + score = Convert.ToInt32(module.Attribute("score")?.Value ?? "0"); + flawsBySeverity = new Dictionary(); + flawsBySeverity[0] = Convert.ToInt32(module.Attribute("numflawssev0")?.Value ?? "0"); + flawsBySeverity[1] = Convert.ToInt32(module.Attribute("numflawssev1")?.Value ?? "0"); + flawsBySeverity[2] = Convert.ToInt32(module.Attribute("numflawssev2")?.Value ?? "0"); + flawsBySeverity[3] = Convert.ToInt32(module.Attribute("numflawssev3")?.Value ?? "0"); + flawsBySeverity[4] = Convert.ToInt32(module.Attribute("numflawssev4")?.Value ?? "0"); + flawsBySeverity[5] = Convert.ToInt32(module.Attribute("numflawssev5")?.Value ?? "0"); + var cx = cwes.Where(c => c.details.Any(d => d.module.Equals(name, StringComparison.CurrentCultureIgnoreCase))); + flaws = cx.SelectMany(c => c.details.Where(d => d.module.Equals(name, StringComparison.CurrentCultureIgnoreCase)).Select(d => new ModuleFlaw(d))) + .GroupBy(d => $"{d.type}{d.sourcefile}{d.line}") + .Select(grp => new ModuleSummary + { + key = grp.Key, + source = grp.First(), + count = grp.Count() + }) + .OrderBy(grp => grp.source.sourcefile).ThenBy(grp => grp.source.line).ThenBy(grp => grp.source.type).ToList(); + } + + object ToDump() => new + { + Info = new + { + name, + score = score.ToString().PadLeft(3), + totalNumberOfFlaws = totalNumberOfFlaws.ToString().PadLeft(5), + numberOfImportantFlaws = numberOfImportantFlaws.ToString().PadLeft(5) + }, + summary, + flaws = flawList + }; +} + +internal class ModuleSummary +{ + public string key { get; set; } + public ModuleFlaw source { get; set; } + public int count { get; set; } +} + +internal class Severity +{ + public string Level => severity.SeverityLabel(); + internal int severity { get; set; } + public int Count { get; set; } + + object ToDump() => new + { + Level, + Count = Count.ToString().PadLeft(4) + }; +} + +internal class ModuleFlaw +{ + public string type { get; set; } + internal string sourcefile { get; set; } + public string path => string.IsNullOrEmpty(sourcefile) ? "n/a" : System.IO.Path.GetDirectoryName(sourcefile); + public string file => string.IsNullOrEmpty(sourcefile) ? "n/a" : System.IO.Path.GetFileName(sourcefile); + public int count { get; set; } + public int line { get; set; } + public int issueid { get; set; } + public int severity { get; set; } + public int cweid { get; set; } + public string cwename { get; set; } + public string remediation_status{ get; set; } + public int categoryid { get; set; } + public bool hasMitigations { get; set; } + + public ModuleFlaw(XElement element) + { + var cwe = element.Ancestors().Where(e => e.Name.LocalName == "cwe").LastOrDefault(); + cwename = cwe.Attribute("cwename")?.Value ?? ""; + hasMitigations = element.Descendants().Any(sfd => sfd.Name.LocalName == "mitigations"); + var regex = new Regex(@"\.!newinit_0_[0-9]|mscorlib_dll|system_xml_dll|system_web_dll|system_data_dll|system_directoryservices_dll|system_dll\."); + type = regex.Replace(element.Attribute("type")?.Value, "").Trim(new[] { '.' }); + sourcefile = System.IO.Path.Combine((element.Attribute("sourcefilepath")?.Value ?? "").Replace("/jazz new", ""), + element.Attribute("sourcefile")?.Value ?? ""); + remediation_status = element.Attribute("remediation_status")?.Value ?? ""; + line = Convert.ToInt32(element.Attribute("line")?.Value ?? "0"); + count = Convert.ToInt32(element.Attribute("count")?.Value ?? "0"); + issueid = Convert.ToInt32(element.Attribute("issueid")?.Value ?? "0"); + severity = Convert.ToInt32(element.Attribute("severity")?.Value ?? "0"); + cweid = Convert.ToInt32(element.Attribute("cweid")?.Value ?? "0"); + categoryid = Convert.ToInt32(element.Attribute("categoryid")?.Value ?? "0"); + } + + public ModuleFlaw(Flaw flaw) + { + hasMitigations = flaw.hasMitigations; + type = flaw.type; + sourcefile = flaw.sourcefile; + line = flaw.line; + } + + object ToDump() => new + { + categoryid = categoryid.ToString().PadLeft(5), + cweid = cweid.ToString().PadLeft(5), + hasMitigations, + type, + path, + file, + line = line.ToString().PadLeft(5), + count = count.ToString().PadLeft(5), + issueid = issueid.ToString().PadLeft(5), + severity = severity.SeverityLabel() + }; + +} + +internal class Flaw : ModuleFlaw +{ + public string module { get; set; } + public string description { get; set; } + + public Flaw(XElement element) + : base(element) + { + module = string.Join("\r\n", element.Attribute("module")?.Value.Split("/".ToCharArray())); + description = element.Attribute("description")?.Value; + } + + object ToDump() => new + { + Info = new + { + categoryid = $"{categoryid.CategoryLabel()} ({categoryid})", + cweid = cweid.ToString().PadLeft(5), + cwename, + hasMitigations, + type, + path, + file, + line = line.ToString().PadLeft(5), + count = count.ToString().PadLeft(5), + issueid = issueid.ToString().PadLeft(5), + severity = severity.SeverityLabel() + }, + description + }; +} + +internal class Cwe +{ + public int id { get; set; } + public string category { get; set; } + public string name { get; set; } + public int severity { get; set; } + public int count { get; set; } + public string recommendation { get; set; } + public IEnumerable details { get; set; } + + public Cwe(XElement module) + { + var categoryElement = module.Parent; + var severityElement = categoryElement.Parent; + severity = Convert.ToInt32(severityElement.Attribute("level")?.Value ?? "0"); + + category = categoryElement.Attribute("categoryname")?.Value ?? ""; + var recommendations = categoryElement.Descendants().Where(d => d.Name.LocalName == "recommendations"); + var content = recommendations.Descendants(); + recommendation = string.Join("\r\n", content.ToList().Select(n => (n.Name.LocalName == "bulletitem" ? "- " : "") + n.Attribute("text")?.Value)); + + id = Convert.ToInt32(module.Attribute("cweid").Value); + name = module.Attribute("cwename").Value; + + var staticFlaws = module.XPathSelectElements("./*").Where(m => m.Name.LocalName == "staticflaws"); + var flaws = (staticFlaws.SelectMany(m => m.XPathSelectElements("./*").Where(sf => sf.Name.LocalName == "flaw")))?.ToList() + .Select(f => new Flaw(f)) + .GroupBy(grp => new { grp.module, grp.type, grp.description }) + .Select(x => x.First()); + + details = flaws + .Where(f => !f.hasMitigations) + .OrderBy(d => d.type).ThenBy(d => d.module).ThenBy(d => d.description); + + count = details.Count(); + } + + object ToDump() => new + { + Info = new + { + Name = name, + Category = $"{category} ({id})", + Severity = severity.SeverityLabel(), + wo_Tests = count + }, + recommendation + + }; +} \ No newline at end of file diff --git a/Veracode/Veracode Module Analytics.linq b/Veracode/Veracode Module Analytics.linq new file mode 100644 index 0000000..1c3c1ed --- /dev/null +++ b/Veracode/Veracode Module Analytics.linq @@ -0,0 +1,293 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +//private string xmlAnalyticsFile = @"C:\Users\tlamb\Downloads\detailedreport_Strata_Jazz_Web_Jazz_web_201911511115217.xml"; +private string xmlAnalyticsFile = @"C:\Users\tlamb\Downloads\detailedreport_Strata_Jazz_Web_Strata_Jazz_Web_201953102954843.xml"; + +public static class IntExtensions +{ + public static string SeverityLabel(this int severity) + { + switch (severity) + { + case 5: return "Very High"; + case 4: return "High"; + case 3: return "Medium"; + case 2: return "Low"; + case 1: return "Very Low"; + default: return "Informational"; + } + } +} + +internal class Module +{ + public string name { get; set; } + public int score { get; set; } + public int totalNumberOfFlaws => flawsBySeverity.Values.Sum(); + public int numberOfImportantFlaws => flawsBySeverity.Where(f => f.Key > 2).Select(f => f.Value).Sum(); + private Dictionary flawsBySeverity { get; set; } + public string flawsSummary => totalNumberOfFlaws > 0 + ? flawsBySeverity.Where(f => f.Value > 0).OrderByDescending(f => f.Key).Aggregate(new StringBuilder("Severity\n"), (x, y) => + x.Append($"{y.Key.SeverityLabel()}: {y.Value}\r\n")).ToString().TrimEnd(new[] { '\r', '\n' }) + : ""; + public IEnumerable flaws { get; set; } + public string flawList => !flaws.Any() + ? "" : flaws.Aggregate(new StringBuilder("path\tfile\tline\ttype\n"), (x, y) => + x.AppendLine($"{(string.IsNullOrEmpty(y.sourcefile) ? "na" : Path.GetDirectoryName(y.sourcefile))}\t" + + $"{(string.IsNullOrEmpty(y.sourcefile) ? "na" : Path.GetFileName(y.sourcefile))}\t{y.line}\t{y.type}")).ToString(); + + public Module(XElement module, IEnumerable cwes) + { + name = module.Attribute("name")?.Value; + score = Convert.ToInt32(module.Attribute("score")?.Value ?? "0"); + flawsBySeverity = new Dictionary(); + flawsBySeverity[0] = Convert.ToInt32(module.Attribute("numflawssev0")?.Value ?? "0"); + flawsBySeverity[1] = Convert.ToInt32(module.Attribute("numflawssev1")?.Value ?? "0"); + flawsBySeverity[2] = Convert.ToInt32(module.Attribute("numflawssev2")?.Value ?? "0"); + flawsBySeverity[3] = Convert.ToInt32(module.Attribute("numflawssev3")?.Value ?? "0"); + flawsBySeverity[4] = Convert.ToInt32(module.Attribute("numflawssev4")?.Value ?? "0"); + flawsBySeverity[5] = Convert.ToInt32(module.Attribute("numflawssev5")?.Value ?? "0"); + var cx = cwes.Where(c => c.details.Any(d => d.module.Equals(name, StringComparison.CurrentCultureIgnoreCase))); + flaws = cx.SelectMany(c => c.details.Where(d => d.module.Equals(name, StringComparison.CurrentCultureIgnoreCase)) + .Select(d => new ModuleFlaw(d))) + //.GroupBy(d => $"{d.type}{d.sourcefile}{d.line}").Select(grp => grp.First()) + .OrderBy(grp => grp.sourcefile).ThenBy(grp => grp.line).ThenBy(grp => grp.type); + } +} + +internal class ModuleFlaw +{ + public string type { get; set; } + public string sourcefile { get; set; } + public int line { get; set; } + public bool hasMitigations { get; set; } + + public ModuleFlaw(XElement element) + { + hasMitigations = element.Descendants().Any(sfd => sfd.Name.LocalName == "mitigations"); + var regex = new Regex(@"\.!newinit_0_[0-9]|mscorlib_dll|system_xml_dll|system_web_dll|system_data_dll|system_directoryservices_dll|system_dll\."); + type = regex.Replace(element.Attribute("type")?.Value, "").Trim(new[] { '.' }); + sourcefile = System.IO.Path.Combine((element.Attribute("sourcefilepath")?.Value ?? "").Replace("/jazz new", ""), + element.Attribute("sourcefile")?.Value ?? ""); + line = Convert.ToInt32(element.Attribute("line")?.Value ?? "0"); + } + + public ModuleFlaw(Flaw flaw) + { + hasMitigations = flaw.hasMitigations; + type = flaw.type; + sourcefile = flaw.sourcefile; + line = flaw.line; + } +} + +internal class Flaw : ModuleFlaw +{ + public string module { get; set; } + public string description { get; set; } + public string grace_period_expires { get; set; } + public string remediation_status { get; set; } + public bool remediated => (remediation_status == "Fixed"); + + public Flaw(XElement element) + : base(element) + { + module = string.Join("\r\n", element.Attribute("module")?.Value.Split("/".ToCharArray())); + description = element.Attribute("description")?.Value; + DateTime parsedDate; + var theDate = System.Net.WebUtility.HtmlDecode(element.Attribute("grace_period_expires")?.Value).Replace(" UTC", "Z"); + if (DateTime.TryParse(theDate, out parsedDate)) + { + grace_period_expires = parsedDate.ToShortDateString(); + } + else + { + grace_period_expires = string.Empty; + } + remediation_status = element.Attribute("remediation_status")?.Value; + } + +} + +internal class Cwe +{ + public int id { get; set; } + public string category { get; set; } + public string name { get; set; } + public int severity { get; set; } + public int count { get; set; } + public string recommendation { get; set; } + public IEnumerable details { get; set; } + + public Cwe(XElement module) + { + var categoryElement = module.Parent; + var severityElement = categoryElement.Parent; + severity = Convert.ToInt32(severityElement.Attribute("level")?.Value ?? "0"); + + category = categoryElement.Attribute("categoryname")?.Value ?? ""; + var recommendations = categoryElement.Descendants().Where(d => d.Name.LocalName == "recommendations"); + var content = recommendations.Descendants(); + recommendation = string.Join("\r\n", content.ToList().Select(n => (n.Name.LocalName == "bulletitem" ? "- " : "") + n.Attribute("text")?.Value)); + + id = Convert.ToInt32(module.Attribute("cweid").Value); + name = module.Attribute("cwename").Value; + + var staticFlaws = module.XPathSelectElements("./*").Where(m => m.Name.LocalName == "staticflaws"); + var flaws = (staticFlaws.SelectMany(m => m.XPathSelectElements("./*").Where(sf => sf.Name.LocalName == "flaw")))?.ToList() + .Select(f => new Flaw(f)); + //.GroupBy(grp => new { grp.module, grp.type, grp.description }) + //.Select(x => x.First()); + + details = flaws + //.Where(f => !f.hasMitigations) + .OrderBy(d => d.type).ThenBy(d => d.module).ThenBy(d => d.description); + + count = details.Count(); + } +} + +internal IEnumerable ParseVeracodeReport(XDocument xmlDoc) +{ + return from module in xmlDoc.Descendants() + where module.Name.LocalName == "cwe" + && module.Attributes().Any(a => a.Name == "cweid") + orderby Int32.Parse(module.Attribute("cweid").Value) + select new Cwe(module); +} + +void Main() +{ + XDocument xmlDoc = XDocument.Load(xmlAnalyticsFile); + //xmlDoc.DumpFormatted(); + var cwes = ParseVeracodeReport(xmlDoc).Where(cwe => cwe.count > 0); + cwes + .SelectMany(c => c.details.Select(d => new + { + c.severity, + c.category, + c.id, + c.name, + d.type, + d.sourcefile, + line = d.line.ToString(), + d.hasMitigations, + d.module, + d.grace_period_expires, + d.remediation_status, + d.remediated + })) + .Where(c => !c.remediated) + .OrderByDescending(c => c.severity).ThenBy(c => c.category).ThenBy(c => c.module).ThenBy(c => c.sourcefile).ThenBy(c => c.type).ThenBy(c => c.line) + .GroupBy(c => new + { + Severity = c.severity.SeverityLabel(), + Category = c.category, + CWE_Id = c.id.ToString(), + Description = c.name + }, (key, group) => new + { + Severity = key, + Items = group.ToList().Select(g => new + { + g.type, + g.sourcefile, + g.line, + g.hasMitigations, + g.module, + g.grace_period_expires + }) + }) + .Dump(); + // cwes.SelectMany(c => c.details.Select(d => new { c.category, c.name, d.type, d.sourcefile, line = d.line.ToString(), d.hasMitigations, d.module })) + // .Where(c => c.module.Contains(".dss.")) + // .OrderBy(c => c.module).ThenBy(c => c.category).ThenBy(c => c.sourcefile).ThenBy(c => c.type).ThenBy(c => c.line) + // .Dump(); + // cwes.Where(cwe => cwe.count > 1) + // .OrderByDescending(cwe => cwe.severity).ThenByDescending(cwe => cwe.count) + // .Select(cwe => new + // { + // severity = cwe.severity.SeverityLabel(), + // category_id = $"{cwe.category} ({cwe.id})", + // wo_Tests = cwe.count, + // cwe.name, + // cwe.recommendation }) + // .Dump($"Summary: ({cwes.Where(cwe => cwe.count > 1).Count()})"); + // + // var regex = new Regex(@"\.Test\.|\.IntegrationTests\.|\.UnitTests\."); + // var modules = from m in xmlDoc.Descendants() + // where m.Name.LocalName == "module" && m.Parent.Name.LocalName == "modules" + // select new Module(m, cwes); + // modules.Where(m => !regex.IsMatch(m.name) && m.totalNumberOfFlaws > 0) + // .Select(m => new {m.name, m.score, m.totalNumberOfFlaws, m.numberOfImportantFlaws, m.flawsSummary, m.flawList}) + // .Dump($"Modules: ({modules.Count(m => !regex.IsMatch(m.name) && m.totalNumberOfFlaws > 0)})"); + // + // modules.Where(m => !regex.IsMatch(m.name) && m.totalNumberOfFlaws > 0 + // && new [] {"Strata.CS.Jazz.Biz.DSS.Episodes.EpisodeDefinition.dll","Strata.CS.Jazz.Biz.DSS.Episodes.dll","Strata.Administrator.Base.dll"}.Contains(m.name)) + // .Select(m => new { m.name, m.flaws }) + // .Dump($"Module Flaws: ({modules.Count(m => !regex.IsMatch(m.name) && m.totalNumberOfFlaws > 0)})"); + // + // cwes.Where(cwe => cwe.count > 1) + // .OrderBy(cwe => cwe.id).ToList() + // .ForEach(cwe => cwe.details.Dump($"ID: {cwe.id} {cwe.name} ({cwe.count})")); + // //JsonConvert.SerializeObject(cwes, Newtonsoft.Json.Formatting.Indented).Dump("Json"); +} \ No newline at end of file diff --git a/Veracode/Veracode Solution Manager.linq b/Veracode/Veracode Solution Manager.linq new file mode 100644 index 0000000..f93d148 --- /dev/null +++ b/Veracode/Veracode Solution Manager.linq @@ -0,0 +1,80 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var regex = new Regex("^Project[^=]+= ([^,]+), \"([^\"]+).+$"); +var veracode = File.ReadAllLines(@"C:\git\jazz\jazz web.sln") + .Where(x => x.StartsWith("Project")) + .Select(x => regex.Matches(x)?[0].Groups[1]?.Value); + +//File.ReadAllLines(@"C:\git\jazz\jazz build all.sln") +// .Where(x => x.StartsWith("Project")).Dump(); + +var solution = File.ReadAllLines(@"C:\git\jazz\jazz build all.sln") + .Where(x => x.StartsWith("Project")) + .Select(x => new + { + name = regex.Matches(x)?[0].Groups[1]?.Value.Trim('"'), + project = regex.Matches(x)?[0].Groups[2]?.Value + }) + .Where(x => !veracode.Contains(x.project)) + .Where(x => !x.project.StartsWith("Test") && !x.project.StartsWith("Internal Tools")) + .OrderBy(x => x.name); +solution.Dump(); \ No newline at end of file diff --git a/Veracode/Veracode parsing report for the modules.linq b/Veracode/Veracode parsing report for the modules.linq new file mode 100644 index 0000000..128e2df --- /dev/null +++ b/Veracode/Veracode parsing report for the modules.linq @@ -0,0 +1,74 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +XDocument xmlDoc = XDocument.Load(@"C:\Users\tlamb\Downloads\detailedreport_Strata_Jazz_Web_Jazz_web_201911511115217.xml"); + xmlDoc.DumpFormatted(); + xmlDoc.XPathSelectElements("./detailedreport/severity/category/cwe").Dump(); + + var rows = from row in xmlDoc.XPathSelectElements("//node()[local-name(.) = 'module']") select row; + var modules = rows.SelectMany(row => row.Attributes().Where(a => a.Name == "name").Select(a => a.Value)); + + //modules.Distinct().OrderBy(m => m).Dump(); + + var cwerows = from row in xmlDoc.XPathSelectElements("//node()[local-name(.) = 'cwe']") select row; + var cwes = cwerows.SelectMany(c => c.Attributes().Where(a => a.Name == "cweid" && a.Value == "73").Select(a => a.Parent)); + + cwes.Dump(); \ No newline at end of file diff --git a/Working with Reports SortArgs.linq b/Working with Reports SortArgs.linq new file mode 100644 index 0000000..f1e044d --- /dev/null +++ b/Working with Reports SortArgs.linq @@ -0,0 +1,87 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var reportGUIDs = new Guid[] { + new Guid("e06ef5e3-102d-4563-8e22-9c3ecbf6e671"), + new Guid("d0a5c9dc-c5d7-4a0b-a0f9-282735a44782"), + new Guid("b2575e8d-24bf-4f19-90c4-233d26a705d0"), + new Guid("28aa8af2-d21b-4307-85f0-cf7906363742") +}; +(from report in REReports + where reportGUIDs.Contains(report.ReportGUID) + select new + { + Report = report, + Setup = (from s in REDSCubeReportSetups + where s.ReportGUID == report.ReportGUID + select new + { + s.DSCubeReportSetupGUID, + s.ReportGUID, + s.LaunchMode, + s.IsDrilldownIndented, + s.Style, + s.IsAutoRefresh, + SortArgs = s.SortArgsXML.XMLToJson(Newtonsoft.Json.Formatting.Indented), + }), + DataSources = (from ds in REDSCubeReportDataSourceLinks where ds.ReportGUID == report.ReportGUID select ds) + + }).Dump(); \ No newline at end of file diff --git a/archive_pagelogs for reports homr.linq b/archive_pagelogs for reports homr.linq new file mode 100644 index 0000000..c468ef3 --- /dev/null +++ b/archive_pagelogs for reports homr.linq @@ -0,0 +1,68 @@ + + + 4f885e7e-d8bb-427c-a54e-8e3e1c3137a7 + true + IOAK-SQL-LOG-01.sdt.local + jazz log prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +(from pl in Archive_PageLogs +where pl.Url.StartsWith("/cci/Reports/Home.aspx") + && pl.DateTimeStamp > new DateTime(2020, 1, 1) +select pl) +.GroupBy(pl => pl.DatabaseName, (g, d) => new {d.First().DatabaseName, Count = d.Count()}) +.OrderBy(pl => pl.DatabaseName) +.Dump(); \ No newline at end of file diff --git a/cci tables.linq b/cci tables.linq new file mode 100644 index 0000000..f012730 --- /dev/null +++ b/cci tables.linq @@ -0,0 +1,121 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +var important = new[] { +"CaseTypeEntity", +"CaseTypeFamilyMetrics", +"ChargeCaptureMetricGoal", +"ChargeCodeConfig", +"ChargeCodeCostDetail", +"ClinicalGrowthMetricGoal", +"Configuration", +"CustomOppMetricLink", +"CustomOpportunity", +"DepartmentPatientADT", +"DepartmentPatientCensus", +"DepartmentPatientDailyCensus", +"DepartmentPatientHourlyADTCensus", +"DepartmentPatientHourlyCensus", +"DepartmentStaffHourlyCensus", +"DirectCostMetricGoal", +"EmployeeWorkedHours", +"FactMetric", +"FactOpportunityMetric", +"FactOpportunitySavings", +"FreeFormInitiativeTrackingData", +"FreeFormOpportunity", +"GLDepartment", +"GLOpportunity", +"Initiative", +"InitiativeComment", +"InitiativeCriteria", +"InitiativeScore", +"InitiativeWorkflowHistory", +"FactPatientEncounterSummary", +"VariationEncounterSaving", +"VariationEncounterSavingInfo"}; +var tables = ExecuteQueryDynamic(@"SELECT c.TABLE_NAME, + c.COLUMN_NAME, + c.ORDINAL_POSITION, + c.DATA_TYPE, + CASE c.IS_NULLABLE WHEN 'no' THEN 'not null' ELSE '' END [Nullability], + CASE WHEN c.COLUMN_DEFAULT IS NULL THEN '' ELSE c.COLUMN_DEFAULT END COLUMN_DEFAULT +FROM INFORMATION_SCHEMA.COLUMNS AS c +INNER JOIN INFORMATION_SCHEMA.TABLES t ON c.TABLE_NAME = t.TABLE_NAME AND t.TABLE_TYPE = 'BASE TABLE' +WHERE c.TABLE_SCHEMA = 'cci' AND c.TABLE_CATALOG = 'jazz dev master Prod' +ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION") +.Select(t => new +{ + table = t.TABLE_NAME as string, + column = t.COLUMN_NAME as string, + position = t.ORDINAL_POSITION as int?, + dataType = t.DATA_TYPE as string, + nullability = t.Nullability as string, + columnDefault = t.COLUMN_DEFAULT as string +}).ToList(); +tables +.Where(t => !important.Contains(t.table)) +.GroupBy(t => t.table, (g, d) => d.OrderBy(c => c.position)) +.ToList() +.ForEach(x => +{ + x.Select(t => new { t.column, t.dataType, t.nullability, t.columnDefault }).Dump(x.First().table); +}); \ No newline at end of file diff --git a/consolidate CaseTypeFamily information.linq b/consolidate CaseTypeFamily information.linq new file mode 100644 index 0000000..d825f46 --- /dev/null +++ b/consolidate CaseTypeFamily information.linq @@ -0,0 +1,398 @@ + + + 580b3b8d-cc02-4a68-8fbd-d1ec374a25f2 + true + D0001-sql-11.sdt.local + jazz dev master Prod + true + + AWSSDK.DynamoDBv2 + AWSSDK.S3 + Newtonsoft.Json + Amazon.DynamoDBv2.DataModel + Amazon.DynamoDBv2 + Amazon.DynamoDBv2.DocumentModel + Amazon.DynamoDBv2.Model + + +public static Dictionary> Versions = new Dictionary>(); + +void Main() +{ + Versions = (from v in CaseTypeFamilyVersions select v) + .ToDictionary(v => v.CaseTypeFamilyVersionID, t => new Tuple(t.StartDate, t.EndDate)); + var aprdrg = (from aprDto in CaseTypeFamilyMappingAPRDRGs + join ctfDto in CaseTypeFamilies on aprDto.CaseTypeFamilyID equals ctfDto.CaseTypeFamilyID + select new AllCaseTypeFamily( + ctfDto.CaseTypeFamilyID, + ctfDto.CaseTypeFamilyGUID, + ctfDto.Name, + ctfDto.CaseTypeFamilyGlobalID, + aprDto.APRDRGCode, + aprDto.CaseTypeFamilyVersionID)).ToList(); + var msdrg = (from icd10Dto in CaseTypeFamilyMappingICD10s + join ctfDto in CaseTypeFamilies on icd10Dto.CaseTypeFamilyID equals ctfDto.CaseTypeFamilyID + select new AllCaseTypeFamily( + ctfDto.CaseTypeFamilyID, + ctfDto.CaseTypeFamilyGUID, + ctfDto.Name, + ctfDto.CaseTypeFamilyGlobalID, + icd10Dto.SkipICD, + icd10Dto.ICD10Code, + icd10Dto.MSDRGCode, + icd10Dto.CaseTypeFamilyVersionID)).ToList(); + var cpt = (from cptDto in CaseTypeFamilyMappingCPTs + join ctfDto in CaseTypeFamilies on cptDto.CaseTypeFamilyID equals ctfDto.CaseTypeFamilyID + select new AllCaseTypeFamily( + ctfDto.CaseTypeFamilyID, + ctfDto.CaseTypeFamilyGUID, + ctfDto.Name, + ctfDto.CaseTypeFamilyGlobalID, + cptDto.CaseTypeFamilyVersionID, + cptDto.CPTCode)).ToList(); + //cpt.Dump(nameof(cpt)); + var allCaseTypeFamily = aprdrg.Union(msdrg).Union(cpt) + .OrderBy(x => x.CaseTypeFamilyID) + .ThenByDescending(x => x.CaseTypeFamilyVersionID); + var globalCaseTypeFamily = allCaseTypeFamily + .GroupBy(ctf => new { ctf.CaseTypeFamilyID, ctf.CaseTypeFamilyGUID, ctf.Name, ctf.CaseTypeFamilyGlobalID, ctf.CaseTypeFamilyVersionID }, + (g, d) => new GlobalCaseTypeFamily( + g.CaseTypeFamilyID, + g.CaseTypeFamilyGUID, + g.Name, + g.CaseTypeFamilyGlobalID, + g.CaseTypeFamilyVersionID, + d.First().StartDate, + d.First().EndDate, + d.Where(x => !string.IsNullOrEmpty(x.APRDRGCode)).Select(x => x.APRDRGCode), + d.Where(x => !string.IsNullOrEmpty(x.CPTCode)).Select(x => x.CPTCode), + d + .Where(x => (string.IsNullOrEmpty(x.APRDRGCode) || string.IsNullOrEmpty(x.CPTCode)) && !x.SkipICD) + .Select(x => new ICD10Code(x.ICD10Code, x.MSDRGCode)), + d + .Where(x => (string.IsNullOrEmpty(x.APRDRGCode) || string.IsNullOrEmpty(x.CPTCode)) && x.SkipICD) + .Select(x => new ICD10Code(x.ICD10Code, x.MSDRGCode)) + )); + globalCaseTypeFamily.Dump(); +/* + try + { + var config = new AmazonDynamoDBConfig + { + ServiceURL = "http://localhost:8000" + }; + var client = new AmazonDynamoDBClient(config); + var context = new DynamoDBContext(client); + DeleteTable(client, nameof(GlobalCaseTypeFamily)); + CreateTableGlobalCaseTypeFamily(client); + var table = Amazon.DynamoDBv2.DocumentModel.Table.LoadTable(client, nameof(GlobalCaseTypeFamily)); + globalCaseTypeFamily.ToList() + .ForEach(ctf => + { + table.PutItem(Document.FromJson(JsonConvert.SerializeObject(ctf))); + }); + } + catch (Exception ex) + { + ex.Dump(); + throw; + } + */ + //var result = JsonConvert.SerializeObject(globalCaseTypeFamily); + //result.Dump(nameof(globalCaseTypeFamily)); + + // Util.WriteCsv(result, @"D:\CaseTypeFamily.csv"); + //System.IO.File.WriteAllText(@"D:\CaseTypeFamily.json", JsonConvert.SerializeObject(result, Newtonsoft.Json.Formatting.Indented)); +} + +private static void CreateTableGlobalCaseTypeFamily(AmazonDynamoDBClient client) +{ + string tableName = nameof(GlobalCaseTypeFamily); + var response = client.CreateTable(new CreateTableRequest + { + TableName = tableName, + AttributeDefinitions = new List() + { + new AttributeDefinition + { + AttributeName = "PartitionKey", + AttributeType = "S" + }, + new AttributeDefinition + { + AttributeName = "CaseTypeFamilyID", + AttributeType = "N" + }, + new AttributeDefinition + { + AttributeName = "CaseTypeFamilyGUID", + AttributeType = "S" + }, + new AttributeDefinition + { + AttributeName = "Name", + AttributeType = "S" + }, + new AttributeDefinition + { + AttributeName = "CaseTypeFamilyGlobalID", + AttributeType = "S" + } + }, + KeySchema = new List() + { + new KeySchemaElement() + { + AttributeName = "PartitionKey", + KeyType = "HASH" + }, + new KeySchemaElement + { + AttributeName = "CaseTypeFamilyID", + KeyType = "RANGE" + } + } + }); + WaitTillTableCreated(client, tableName, response); +} + +#region AWS DynamoDB Helpers + +private static void DeleteTable(AmazonDynamoDBClient client, string tableName) +{ + try + { + var deleteTableResponse = client.DeleteTable(new DeleteTableRequest() + { + TableName = tableName + }); + WaitTillTableDeleted(client, tableName, deleteTableResponse); + } + catch (ResourceNotFoundException) + { + // There is no such table. + } +} + +private static void WaitTillTableCreated(AmazonDynamoDBClient client, string tableName, + CreateTableResponse response) +{ + var tableDescription = response.TableDescription; + + string status = tableDescription.TableStatus; + + Console.WriteLine(tableName + " - " + status); + + // Let us wait until table is created. Call DescribeTable. + while (status != "ACTIVE") + { + System.Threading.Thread.Sleep(5000); // Wait 5 seconds. + try + { + var res = client.DescribeTable(new DescribeTableRequest + { + TableName = tableName + }); + Console.WriteLine("Table name: {0}, status: {1}", res.Table.TableName, + res.Table.TableStatus); + status = res.Table.TableStatus; + } + // Try-catch to handle potential eventual-consistency issue. + catch (ResourceNotFoundException) + { } + } +} + +private static void WaitTillTableDeleted(AmazonDynamoDBClient client, string tableName, + DeleteTableResponse response) +{ + var tableDescription = response.TableDescription; + + string status = tableDescription.TableStatus; + + Console.WriteLine(tableName + " - " + status); + + // Let us wait until table is created. Call DescribeTable + try + { + while (status == "DELETING") + { + System.Threading.Thread.Sleep(5000); // wait 5 seconds + + var res = client.DescribeTable(new DescribeTableRequest + { + TableName = tableName + }); + Console.WriteLine("Table name: {0}, status: {1}", res.Table.TableName, + res.Table.TableStatus); + status = res.Table.TableStatus; + } + } + catch (ResourceNotFoundException) + { + // Table deleted. + } +} + +#endregion + +public class ICD10Code +{ + [DynamoDBProperty] + public string ICD10_Code { get; set; } + [DynamoDBProperty] + public string MSDRGCode { get; set; } + + public ICD10Code() + { + ICD10_Code = string.Empty; + MSDRGCode = string.Empty; + } + + public ICD10Code(string icd10code, string msdrgcode) + { + ICD10_Code = icd10code; + MSDRGCode = msdrgcode; + } +} + +[DynamoDBTable("GlobalCaseTypeFamily")] +public class GlobalCaseTypeFamily +{ + [DynamoDBHashKey] + public string PartitionKey => $"{CaseTypeFamilyVersionID}|{CaseTypeFamilyID}"; + [DynamoDBProperty] + public int CaseTypeFamilyID { get; set; } + [DynamoDBProperty] + public Guid CaseTypeFamilyGUID { get; set; } + [DynamoDBProperty] + public string Name { get; set; } + [DynamoDBProperty] + public string CaseTypeFamilyGlobalID { get; set; } + [DynamoDBProperty] + public int CaseTypeFamilyVersionID { get; set; } + [DynamoDBProperty] + public DateTime StartDate { get; set; } + [DynamoDBProperty] + public DateTime EndDate { get; set; } + [DynamoDBProperty] + public List APRDRGCodes { get; set; } + [DynamoDBProperty] + public List CPTCodes { get; set; } + [DynamoDBProperty] + public List ICD10Codes { get; set; } + [DynamoDBProperty] + public List SkipICD10Codes { get; set; } + + public GlobalCaseTypeFamily() + { + CaseTypeFamilyID = -1; + CaseTypeFamilyGUID = Guid.Empty; + Name = string.Empty; + CaseTypeFamilyGlobalID = string.Empty; + CaseTypeFamilyVersionID = -1; + StartDate = DateTime.MinValue; + EndDate = DateTime.MaxValue; + APRDRGCodes = new List(); + CPTCodes = new List(); + } + + public GlobalCaseTypeFamily(int caseTypeFamilyID, Guid caseTypeFamilyGuid, string name, string caseTypeFamilyGlobalID, int caseTypeFamilyVersionID, + DateTime startDate, DateTime endDate) + { + CaseTypeFamilyID = caseTypeFamilyID; + CaseTypeFamilyGUID = caseTypeFamilyGuid; + Name = name; + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + CaseTypeFamilyVersionID = caseTypeFamilyVersionID; + StartDate = startDate; + EndDate = endDate; + } + + public GlobalCaseTypeFamily(int caseTypeFamilyID, Guid caseTypeFamilyGuid, string name, string caseTypeFamilyGlobalID, int caseTypeFamilyVersionID, + DateTime startDate, DateTime endDate, + IEnumerable aprdrgcodes, + IEnumerable cptcodes, + IEnumerable icd10codes, + IEnumerable skipicd10codes) + : this(caseTypeFamilyID, caseTypeFamilyGuid, name, caseTypeFamilyGlobalID, caseTypeFamilyVersionID, startDate, endDate) + { + APRDRGCodes = aprdrgcodes.ToList(); + CPTCodes = cptcodes.ToList(); + ICD10Codes = icd10codes.ToList(); + SkipICD10Codes = skipicd10codes.ToList(); + } +} + +public class AllCaseTypeFamily +{ + public int CaseTypeFamilyID { get; set; } + public Guid CaseTypeFamilyGUID { get; set; } + public string Name { get; set; } + public string CaseTypeFamilyGlobalID { get; set; } + public string APRDRGCode { get; set; } + public bool SkipICD { get; set; } + public string ICD10Code { get; set; } + public string MSDRGCode { get; set; } + public string CPTCode { get; set; } + public int CaseTypeFamilyVersionID { get; set; } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + + public AllCaseTypeFamily() + { + CaseTypeFamilyID = -1; + CaseTypeFamilyGUID = Guid.Empty; + Name = string.Empty; + CaseTypeFamilyGlobalID = string.Empty; + APRDRGCode = string.Empty; + SkipICD = false; + ICD10Code = string.Empty; + MSDRGCode = string.Empty; + CPTCode = string.Empty; + CaseTypeFamilyVersionID = -1; + StartDate = DateTime.MinValue; + EndDate = DateTime.MaxValue; + } + + public AllCaseTypeFamily(int caseTypeFamilyID, Guid caseTypeFamilyGuid, string name, string caseTypeFamilyGlobalID) + : this() + { + CaseTypeFamilyID = caseTypeFamilyID; + CaseTypeFamilyGUID = caseTypeFamilyGuid; + Name = name; + CaseTypeFamilyGlobalID = caseTypeFamilyGlobalID; + } + + public AllCaseTypeFamily(int caseTypeFamilyID, Guid caseTypeFamilyGuid, string name, string caseTypeFamilyGlobalID, int caseTypeFamilyVersionID) + : this(caseTypeFamilyID, caseTypeFamilyGuid, name, caseTypeFamilyGlobalID) + { + CaseTypeFamilyVersionID = caseTypeFamilyVersionID; + if (Versions.ContainsKey(caseTypeFamilyVersionID)) + { + StartDate = UserQuery.Versions[caseTypeFamilyVersionID].Item1; + EndDate = UserQuery.Versions[caseTypeFamilyVersionID].Item2; + } + } + + public AllCaseTypeFamily(int caseTypeFamilyID, Guid caseTypeFamilyGuid, string name, string caseTypeFamilyGlobalID, string aprdrgCode, int caseTypeFamilyVersionID) + : this(caseTypeFamilyID, caseTypeFamilyGuid, name, caseTypeFamilyGlobalID, caseTypeFamilyVersionID) + { + APRDRGCode = aprdrgCode; + } + + public AllCaseTypeFamily(int caseTypeFamilyID, Guid caseTypeFamilyGuid, string name, string caseTypeFamilyGlobalID, bool skipICD, string icd10Code, string msdrgCode, int caseTypeFamilyVersionID) + : this(caseTypeFamilyID, caseTypeFamilyGuid, name, caseTypeFamilyGlobalID, caseTypeFamilyVersionID) + { + SkipICD = skipICD; + ICD10Code = icd10Code; + MSDRGCode = msdrgCode; + } + + public AllCaseTypeFamily(int caseTypeFamilyID, Guid caseTypeFamilyGuid, string name, string caseTypeFamilyGlobalID, int caseTypeFamilyVersionID, string cptCode) + : this(caseTypeFamilyID, caseTypeFamilyGuid, name, caseTypeFamilyGlobalID, caseTypeFamilyVersionID) + { + CPTCode = cptCode; + } + +} \ No newline at end of file diff --git a/create StrataSphere Mappings.linq b/create StrataSphere Mappings.linq new file mode 100644 index 0000000..9ba35e2 --- /dev/null +++ b/create StrataSphere Mappings.linq @@ -0,0 +1,107 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +//var reports = from report in REReports select report; +//reports.Dump(); + +var parms = from report in REReports +join module in Folders on report.FolderGUID equals module.FolderGuid into reportModules +from rptModule in reportModules.DefaultIfEmpty() + join setup in REDSCubeReportSetups on report.ReportGUID equals setup.ReportGUID + join parameter in REDSCubeReportParameters on report.ReportGUID equals parameter.ReportGUID + where parameter.Name == "Patient Populations" && parameter.ParameterXML != null && parameter.ParameterXML != "" + select new + { + reportName = report.Name, + module = rptModule.Name, + //parameterName = parameter.Name, + //parameter.ColumnName, + parameterXML = XDocument.Parse(parameter.ParameterXML).Descendants("{http://schemas.datacontract.org/2004/07/Strata.CS.Jazz.Biz.Reporting.Parameters}DSCubeSearchCondition"), + Value = XDocument.Parse(parameter.ParameterXML).Descendants("{http://schemas.datacontract.org/2004/07/Strata.CS.Jazz.Biz.Reporting.Parameters}Value"), + ValueIds = XDocument.Parse(parameter.ParameterXML).Descendants("{http://schemas.datacontract.org/2004/07/Strata.CS.Jazz.Biz.Reporting.Parameters}ValueIDArray") + }; +parms.ToList().Where(p => p.parameterXML.Any()).OrderBy(r => r.reportName) +.Select(p => new +{ + p.reportName, + p.module, + values = p.Value.FirstOrDefault()?.Value.Split(new[] { ',' }).Select(v => v.Trim()), + valueIds = p.ValueIds.Descendants().Select(vi => vi.Value) +}).Dump(); + +var mappings = parms.ToList().Where(p => p.parameterXML.Any()).ToList() +.SelectMany(p => from ci in DimClinicalIndicators + join def in Definitions on ci.Name equals def.Name + where p.ValueIds.Descendants().Select(vi => Regex.Replace(vi.Value, @"[^\d]", "")).ToList().Contains(ci.ClinicalIndicatorID.ToString()) + select new { id = ci.ClinicalIndicatorID, Guid = ci.MemberGUID, name = ci.Name, definitionGuid = def.Id } +).Distinct().OrderBy(p => p.name); +mappings.Dump(); + +var sql = "INSERT INTO dbo.StandardDefinitionMapping ( StandardDefinitionGUID, StandardDefinitionName, StandardDefinitionType, MappingMemberValue )\r\nValues " + string.Join(",\r\n ", +mappings.Select(y => $"('{y.definitionGuid}','[Patient Populations].[Patient Populations].&[{y.id}]','Patient Populations','{y.name}')")); +sql.Dump(); \ No newline at end of file diff --git a/date updates/query1.linq b/date updates/query1.linq new file mode 100644 index 0000000..d278f0d --- /dev/null +++ b/date updates/query1.linq @@ -0,0 +1,16 @@ + + +var startDate = DateTime.Now.Date; +var endOfMonth = startDate.AddMonths(1).AddDays(-1).Date; +endOfMonth.Dump(); +endOfMonth.Subtract(startDate).TotalDays.Dump(); +endOfMonth = endOfMonth.AddMonths(1).AddDays(-1).Date; +endOfMonth.Dump(); +endOfMonth.Subtract(startDate).TotalDays.Dump(); +endOfMonth = endOfMonth.AddMonths(1).AddDays(-1).Date; +endOfMonth.Dump(); +endOfMonth.Subtract(startDate).TotalDays.Dump(); +$"{endOfMonth:d}".Dump(); +endOfMonth.ToShortDateString().Dump(); +$"{endOfMonth}".Dump(); +endOfMonth.ToString().Dump(); \ No newline at end of file diff --git a/date updates/query2.linq b/date updates/query2.linq new file mode 100644 index 0000000..dba8e34 --- /dev/null +++ b/date updates/query2.linq @@ -0,0 +1,63 @@ + + +void Main() +{ + var prefix = "fpes"; + if (prefix != "") prefix += "."; + var baselineEndDate = new DateTime(2018, 4, 1); + Enumerable.Range(0, 12).ToList() + .Aggregate("", (x, y) => + { + var result = $"{x} or\r\n({prefix}FiscalYearID = {FiscalMonth.GetFiscalYearID(baselineEndDate.Month, baselineEndDate.Year)}" + + $" and {prefix}FiscalMonthID = {baselineEndDate.Month})"; + baselineEndDate = baselineEndDate.AddMonths(-1); + return result; + }).Substring(5).Dump(); + + baselineEndDate = new DateTime(2018, 4, 1); + var clause = ""; + Enumerable.Range(0, 12) + .ForEach(i => + { + clause += + $"\r\n({prefix}FiscalYearID = {FiscalMonth.GetFiscalYearID(baselineEndDate.Month, baselineEndDate.Year)} and {prefix}FiscalMonthID = {baselineEndDate.Month}) or "; + baselineEndDate = baselineEndDate.AddMonths(-1); + }); + + clause = clause.Substring(0, clause.Length - 3); + clause.Dump(); +} + +// Define other methods and classes here + +public class FiscalMonth +{ + + public static int GetFiscalYearID(int calendarMonth, int calendarYear) + { + var endMonth = DBSetting.General.FiscalYearEndMonth; + return (calendarMonth <= endMonth ? calendarYear : calendarYear + 1); + } + +} + +public static class DBSetting +{ + public static class General + { + public static int FiscalYearEndMonth => 12; + } +} + +public static class EnumerableExtensions +{ + + public static void ForEach(this IEnumerable enumeration, Action action) + { + foreach (T item in enumeration) + { + action(item); + } + } + +} \ No newline at end of file diff --git a/dynamic query test.linq b/dynamic query test.linq new file mode 100644 index 0000000..c5ecedf --- /dev/null +++ b/dynamic query test.linq @@ -0,0 +1,16 @@ + + + 580b3b8d-cc02-4a68-8fbd-d1ec374a25f2 + true + D0001-sql-11.sdt.local + jazz dev master Prod + true + + System.Linq.Dynamic + + +var query = Configurations +.Where("FiscalYearId != @0", 2020) +.OrderBy("FiscalYearId descending") +.Select("new(Name as config)"); +query.Dump(); \ No newline at end of file diff --git a/mailgun test with template fake.linq b/mailgun test with template fake.linq new file mode 100644 index 0000000..1b744bc --- /dev/null +++ b/mailgun test with template fake.linq @@ -0,0 +1,174 @@ + + + 40766b24-ff74-431b-b387-6c221ede77cf + true + p3121-sql-02.sdt.local + jazz prd UNC 20180206.1 + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + RestSharp + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + RestSharp + RestSharp.Authenticators + + +private static string baseurl = "https://dev.sdt.local/StrataJazz201931"; +private static Random _rnd; + +void Main() +{ +// var now = DateTime.Today.AddDays(-1 * (7 + ((DateTime.Today.DayOfWeek - DayOfWeek.Monday)) % 7)); +// var staffing = new Staffing +// { +// pr = new PayPeriod +// { +// StartDate = now.AddDays(-14), +// EndDate = now.AddDays(-7) +// }, +// Departments = Enumerable.Range(0, 26).ToList() +// .ConvertAll(e => //new Department { department = +// new DeptInfo($"dept_{e}", Random.Next() * 10m, Random.Next() * 10m, Random.Next() * 10m * Random.Next(-1, 1)) +// //} +// ) +// }; +// var data = JsonConvert.SerializeObject(staffing); +// data.Dump(); + SendMessageByTemplateId(@"{""test"":""Low and behold""}").Content.Dump(); +} + +internal static Random Random +{ + get => _rnd ?? (_rnd = new Random()); + set => _rnd = value; +} + +// Define other methods and classes here +public class Staffing +{ + public PayPeriod pr { get; set; } + public List overall => new List { Departments.FirstOrDefault() }; + public List departments => new List + { + new DeptInfo( + $"Current Pay Period ({pr.endDate:M/dd})", + Departments.Sum(d => d.latest_total_variance), + Departments.Sum(d => d.latest_pay_variance), + Departments.Sum(d => d.latest_flex_variance) + ) + }; + internal List Departments { get; set; } +} + +public class PayPeriod +{ + internal DateTime StartDate { get; set; } + internal DateTime EndDate { get; set; } + public string startDate => StartDate.ToString("MM/dd"); + public string endDate => EndDate.ToString("MM/dd"); +} + +public class Department +{ + public DeptInfo department { get; set; } +} + +public class DeptInfo +{ + public string hyperlink => baseurl; + public string name { get; set; } + internal decimal latest_total_variance { get; set; } + internal decimal latest_pay_variance { get; set; } + internal decimal latest_flex_variance { get; set; } + public string total_variance => $"{latest_total_variance:C}"; + public string pay_variance => $"{latest_pay_variance:C}"; + public string flex_variance => $"{latest_flex_variance:C}"; + public string six_month_total_chart => "graph_sparkline_6_pay_period_-1281183930.png"; + public string six_month_pay_chart => "graph_sparkline_6_pay_period_1140344931.png"; + public string six_month_flex_chart => "graph_sparkline_6_pay_period_489356044.png"; + public string total_color => latest_total_variance >= 0 ? "positive" : "negative"; + public string pay_color => latest_pay_variance >= 0 ? "positive" : "negative"; + public string flex_color => latest_flex_variance >= 0 ? "positive" : "negative"; + + public DeptInfo(string deptName, decimal total, decimal pay, decimal flex) + { + name = deptName; + latest_total_variance = total; + latest_pay_variance = pay; + latest_flex_variance = flex; + } +} + +public static IRestResponse SendMessageByTemplateId(string jsonStr) +{ + RestClient client = new RestClient(); + client.BaseUrl = new Uri("https://api.mailgun.net/v3"); + client.Authenticator = + new HttpBasicAuthenticator("api", + "key-12ea6389d906cef290ad8a0557a3a8c4"); + RestRequest request = new RestRequest(); + request.AddParameter("domain", "notifications-dev.stratanetwork.com", ParameterType.UrlSegment); + request.Resource = "{domain}/messages"; + request.AddParameter("from", "Mailgun Sandbox "); + //request.AddParameter("to", "Dhara "); + //request.AddParameter("to", "Nicole "); + request.AddParameter("to", "Thom Lamb "); + request.AddParameter("to", "Kevin Lamb "); + //request.AddParameter("to", "Shruthi Agni "); + //request.AddParameter("to", "Tucker Debolt "); + request.AddParameter("subject", "Hello Thom Lamb"); + //request.AddParameter("template", "daily_pr_snapshot"); + request.AddParameter("template", "kcl_test"); + request.AddParameter("h:X-Mailgun-Variables", jsonStr); + request.Method = Method.POST; + return client.Execute(request); +} \ No newline at end of file diff --git a/q1.linq b/q1.linq new file mode 100644 index 0000000..62edbaa --- /dev/null +++ b/q1.linq @@ -0,0 +1,58 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.Core + Amazon.Lambda.S3Events + Amazon.Lambda.Serialization.Json + Amazon.Lambda.TestUtilities + AWSSDK.Core + AWSSDK.S3 + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + + +class report +{ + public Guid ReportGUID {get;set;} + public string Category {get;set;} + public string Module {get;set;} + public string Name {get;set;} + public string Description {get;set;} + public string Migration {get;set;} + + public report(Guid reportGuid, string module, string name, string description) + { + ReportGUID = reportGuid; + Module = module; + Name = name; + Description = description; + Category = "Report"; + Migration = string.Empty; + } +}; + +void Main() +{ + var result = procMigrateGenerateAdHocMigration(new Guid("697C3E94-26F8-4F15-9F58-87F54541AD19")); + result.Dump(); + var reportQuery = from rr in REReports + join f in Folders on rr.FolderGUID equals f.FolderGuid + where rr.IsPublished == true + select new report(rr.ReportGUID, f.Name , rr.Name, rr.Description); +// reportQuery.ToList() +// .ForEach(rpt => rpt.Migration = procMigrateGenerateAdHocMigration(rpt.ReportGUID)); + var json = JsonConvert.SerializeObject(reportQuery.ToList().OrderBy(rpt => rpt.Module).ThenBy(rpt => rpt.Name), Newtonsoft.Json.Formatting.Indented); + json.Dump(); + File.WriteAllText(@"C:\Users\tlamb\Documents\Reports.json", json); + +} + diff --git a/q2.linq b/q2.linq new file mode 100644 index 0000000..bfde279 --- /dev/null +++ b/q2.linq @@ -0,0 +1,135 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + System.Threading.Tasks + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + + +// Define other methods and classes here +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 (For details, see https://github.com/awsdocs/amazon-s3-developer-guide/blob/master/LICENSE-SAMPLECODE.) + + +class UploadFileMPUHighLevelAPITest +{ + private const string bucketName = "stratasphere"; + private const string keyName = "reports-list"; + private const string filePath = @"C:\Users\tlamb\Documents\Reports.json"; + // Specify your bucket region (an example region is shown). + private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USEast1; + private static IAmazonS3 s3Client; + + public static void Main() + { + s3Client = new AmazonS3Client(bucketRegion); + UploadFileAsync().Wait(); + } + + private static async Task UploadFileAsync() + { + try + { + var fileTransferUtility = + new TransferUtility(s3Client); + + // Option 1. Upload a file. The file name is used as the object key name. + await fileTransferUtility.UploadAsync(filePath, bucketName); + Console.WriteLine("Upload 1 completed"); + + // Option 2. Specify object key name explicitly. + await fileTransferUtility.UploadAsync(filePath, bucketName, keyName); + Console.WriteLine("Upload 2 completed"); + + // Option 3. Upload data from a type of System.IO.Stream. + using (var fileToUpload = + new FileStream(filePath, FileMode.Open, FileAccess.Read)) + { + await fileTransferUtility.UploadAsync(fileToUpload, + bucketName, keyName); + } + Console.WriteLine("Upload 3 completed"); + + // Option 4. Specify advanced settings. + var fileTransferUtilityRequest = new TransferUtilityUploadRequest + { + BucketName = bucketName, + FilePath = filePath, + StorageClass = S3StorageClass.StandardInfrequentAccess, + PartSize = 6291456, // 6 MB. + Key = keyName, + CannedACL = S3CannedACL.PublicRead + }; + fileTransferUtilityRequest.Metadata.Add("param1", "Value1"); + fileTransferUtilityRequest.Metadata.Add("param2", "Value2"); + + await fileTransferUtility.UploadAsync(fileTransferUtilityRequest); + Console.WriteLine("Upload 4 completed"); + } + catch (AmazonS3Exception e) + { + Console.WriteLine("Error encountered on server. Message:'{0}' when writing an object", e.Message); + } + catch (Exception e) + { + Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message); + } + + } +} diff --git a/q3.linq b/q3.linq new file mode 100644 index 0000000..6ef009b --- /dev/null +++ b/q3.linq @@ -0,0 +1,20 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + + +((SqlConnection)Connection).InfoMessage += (sender, args) => args.Message.Dump(); + +procMigrateGenerateAdHocMigration (new Guid("697C3E94-26F8-4F15-9F58-87F54541AD19")); + diff --git a/q4.linq b/q4.linq new file mode 100644 index 0000000..c2c4bb1 --- /dev/null +++ b/q4.linq @@ -0,0 +1,303 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +private string accessKeyID = "AKIAIZZXT7LVCPR5COFA"; +private string secretKey = "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"; + +void Main() +{ + var process = 3; + var version = (from s in DBSettings where s.Name == "GENERAL_APPVERSION" select s.Setting).SingleOrDefault(); + switch (process) + { + case 1: + var reports = (from rr in REReports + join f in Folders on rr.FolderGUID equals f.FolderGuid + join up in UserProfiles on rr.AuthorUserGUID equals up.UserGUID into ups + from up in ups.DefaultIfEmpty() + where rr.IsPublished == true + orderby f.Name, rr.Name + select new reportBase(rr.ReportGUID, f.Name, rr.Name, rr.Description, up == null ? rr.AuthorFullName : up.UserName, rr.DateCreated, version)) + .ToList(); + PushReportsJson(reports); + break; + case 2: + PullReportsJson(); + break; + case 3: + JsonConvert.SerializeObject(from rr in REReports + join f in Folders on rr.FolderGUID equals f.FolderGuid + join up in UserProfiles on rr.AuthorUserGUID equals up.UserGUID into ups + from up in ups.DefaultIfEmpty() + where rr.IsPublished == true + orderby f.Name, rr.Name + select new reportBase(rr.ReportGUID, f.Name, rr.Name, rr.Description, up == null ? rr.AuthorFullName : up.UserName, rr.DateCreated, version), Newtonsoft.Json.Formatting.Indented) + .Dump(); + break; + case 4: + var test = (JArray)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(from rr in REReports + join f in Folders on rr.FolderGUID equals f.FolderGuid + join up in UserProfiles on rr.AuthorUserGUID equals up.UserGUID into ups + from up in ups.DefaultIfEmpty() + where rr.IsPublished == true + orderby f.Name, rr.Name + select new reportBase(rr.ReportGUID, f.Name, rr.Name, rr.Description, up == null ? rr.AuthorFullName : up.UserName, rr.DateCreated, version), Newtonsoft.Json.Formatting.Indented)); + var modules = (from t in test select (string)t["Module"]).Distinct().ToList(); + modules.Dump(); +// var result = ((JArray)test["Module"]).Distinct().ToList(); +// result.Dump(); + test.Dump(); + break; + default: + var migrations = (from rr in REReports + join f in Folders on rr.FolderGUID equals f.FolderGuid + join up in UserProfiles on rr.AuthorUserGUID equals up.UserGUID into ups + from up in ups.DefaultIfEmpty() + where rr.IsPublished == true + orderby f.Name, rr.Name + select new report(rr.ReportGUID, f.Name, rr.Name, rr.Description, up == null ? rr.AuthorFullName : up.UserName, rr.DateCreated, version)) + .ToList(); + migrations.ForEach(r => + { + var migration = new StringBuilder(); + ((SqlConnection)Connection).InfoMessage += (sender, args) => migration.AppendLine(args.Message); + procMigrateGenerateAdHocMigration(r.ReportGUID); + r.Migration = migration.ToString(); + }); + UploadReports(migrations); + DumpReports(); + break; + } +} + +void PullReportsJson() +{ + var credentials = new BasicAWSCredentials(accessKeyID, secretKey); + using (var client = new AmazonS3Client(credentials, RegionEndpoint.USEast1)) + { + var getRequest = new GetObjectRequest + { + BucketName = "stratasphere", + Key = "Reports.json" + }; + var response = client.GetObject(getRequest); + var reader = new StreamReader(response.ResponseStream); + //reader.ReadToEnd().Dump(); + //reader = new StreamReader(response.ResponseStream); + var reports = JsonConvert.DeserializeObject>(reader.ReadToEnd()); + reports.Select(r => new reportBase(r)).Dump(); + } +} + +void PushReportsJson(List reports) +{ + var credentials = new BasicAWSCredentials(accessKeyID, secretKey); + using (var client = new AmazonS3Client(credentials, RegionEndpoint.USEast1)) + { + var putRequest = new PutObjectRequest + { + BucketName = "stratasphere", + Key = "Reports.json", + ContentType = "text/plain", + ContentBody = JsonConvert.SerializeObject(reports, Newtonsoft.Json.Formatting.None) + }; + client.PutObject(putRequest); + } +} + +void DeleteReports(List reportQuery) +{ + var credentials = new BasicAWSCredentials(accessKeyID, secretKey); + using (var client = new AmazonS3Client(credentials, RegionEndpoint.USEast1)) + { + reportQuery.Select(q => q.Category).Distinct().ToList() + .ForEach(r => + { + var request = new DeleteObjectRequest + { + BucketName = "stratasphere", + Key = r, + }; + try + { + client.DeleteObject(request); + } + catch (Exception e) + { + e.Dump(); + } + }); + } +} + +void UploadReports(List reportQuery) +{ + $"reports: {reportQuery.Count()}".Dump(); + var credentials = new BasicAWSCredentials(accessKeyID, secretKey); + using (var client = new AmazonS3Client(credentials, RegionEndpoint.USEast1)) + { + var response = client.ListBuckets(); + response.Buckets.ForEach(b => $"{b.BucketName} {b.CreationDate}".Dump()); + } + using (var client = new AmazonS3Client(credentials, RegionEndpoint.USEast1)) + { + reportQuery.ToList().ForEach(r => + { + var putRequest = new PutObjectRequest + { + BucketName = "stratasphere", + Key = $"{r.Category}/{r.Module}/{r.ReportGUID}", + ContentType = "text/plain", + ContentBody = JsonConvert.SerializeObject(r, Newtonsoft.Json.Formatting.Indented) + }; + client.PutObject(putRequest); + }); + } + +} + +void DumpReports() +{ + var credentials = new BasicAWSCredentials(accessKeyID, secretKey); + using (var client = new AmazonS3Client(credentials, RegionEndpoint.USEast1)) + { + var request = new Amazon.S3.Model.ListObjectsRequest + { + BucketName = "stratasphere" + }; + + do + { + var response = client.ListObjects(request); + response.Dump(); + + response.S3Objects.Dump(); + response.S3Objects.Where(obj => obj.Key == "Reports.json").Dump(); + + if (response.IsTruncated) + { + request.Marker = response.NextMarker; + } + else + { + request = null; + } + } while (request != null); + } +} + +class reportBase +{ + public Guid ReportGUID { get; set; } + public string Category { get; set; } + public string Module { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string UserName { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime UploadDate { get; set; } + public string DbVersion { get; set; } + + public reportBase(Guid reportGuid, string module, string name, string description, string userName, DateTime createdDate, string dbVersion) + { + ReportGUID = reportGuid; + Module = module; + Name = name; + Description = description; + Category = "Report"; + UserName = userName; + CreatedDate = createdDate; + UploadDate = DateTime.Now; + DbVersion = dbVersion; + } + + public reportBase(report r) + { + ReportGUID = r.ReportGUID; + Module = r.Module; + Name = r.Name; + Description = r.Description; + Category = r.Category; + UserName = r.UserName; + CreatedDate = r.CreatedDate; + UploadDate = r.UploadDate; + DbVersion = r.DbVersion; + } +} + +class report : reportBase +{ + public string Migration { get; set; } + + public report(Guid reportGuid, string module, string name, string description, string userName, DateTime createdDate, string dbVersion) + : base(reportGuid, module, name, description, userName, createdDate, dbVersion) + { + Migration = string.Empty; + } + +}; \ No newline at end of file diff --git a/q5.linq b/q5.linq new file mode 100644 index 0000000..57110bc --- /dev/null +++ b/q5.linq @@ -0,0 +1,120 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-01.sdt.local + jazz dev master + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.ComponentModel.Composition + System.ComponentModel.Composition.Hosting + System.ComponentModel.Composition.Primitives + System.ComponentModel.Composition.ReflectionModel + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + System.Net.Http + System.Net.Http.Headers + System.Numerics + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var version = (from s in DBSettings where s.Name == "GENERAL_APPVERSION" select s.Setting).SingleOrDefault(); + + var reportQuery = (from rr in REReports + join f in Folders on rr.FolderGUID equals f.FolderGuid + join up in UserProfiles on rr.AuthorUserGUID equals up.UserGUID into ups + from up in ups.DefaultIfEmpty() + where rr.IsPublished == true + orderby f.Name, rr.Name + select new report(rr.ReportGUID, f.Name, rr.Name, rr.Description, up == null ? rr.AuthorFullName : up.UserName, rr.DateCreated, version)) + .ToList(); + + reportQuery.ForEach(r => + { + var migration = new StringBuilder(); + ((SqlConnection)Connection).InfoMessage += (sender, args) => migration.AppendLine(args.Message); + procMigrateGenerateAdHocMigration(r.ReportGUID); + r.Migration = migration.ToString(); + }); + + reportQuery.Dump(); +} + +// Define other methods and classes here +class report +{ + public Guid ReportGUID { get; set; } + public string Category { get; set; } + public string Module { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string UserName { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime UploadDate { get; set; } + public string DbVersion { get; set; } + public string Migration { get; set; } + + public report(Guid reportGuid, string module, string name, string description, string userName, DateTime createdDate, string dbVersion) + { + ReportGUID = reportGuid; + Module = module; + Name = name; + Description = description; + Category = "Report"; + UserName = userName; + CreatedDate = createdDate; + UploadDate = DateTime.Now; + DbVersion = dbVersion; + Migration = string.Empty; + } +}; \ No newline at end of file diff --git a/q6.linq b/q6.linq new file mode 100644 index 0000000..e1572b0 --- /dev/null +++ b/q6.linq @@ -0,0 +1,89 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var storeData = File.ReadAllText(@"D:\patientData.json"); + var chartDto = JArray.Parse(storeData).ToObject>(); + chartDto.Select(d => d.HourOfDay).Where(d => d != null).Dump(); + chartDto.Dump(); +} + +// Define other methods and classes here +public class WasteChartDto +{ + public string HoursOfDay { get; set; } + public string HourOfDay { get; set; } + public string DayOfDay { get; set; } + public string DaysOfWeek { get; set; } + + public double Patient25thVolume { get; set; } + public double PatientMedianVolume { get; set; } + public double Patient75thVolume { get; set; } + public double Patient90thVolume { get; set; } + public double Staff25thVolume { get; set; } + public double StaffMedianVolume { get; set; } + public double Staff75thVolume { get; set; } + public double Staff90thVolume { get; set; } + public double OptimalMedianVolume { get; set; } + public double Acuity25thVolume { get; set; } + public double AcuityMedianVolume { get; set; } + public double Acuity75thVolume { get; set; } + + public WasteChartDto() + { + + } + +} \ No newline at end of file diff --git a/q7.linq b/q7.linq new file mode 100644 index 0000000..85e2828 --- /dev/null +++ b/q7.linq @@ -0,0 +1,89 @@ + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + + +void Main() +{ + var storeData = File.ReadAllText(@"D:\patientDataCNE.json"); + var chartDto = JArray.Parse(storeData).ToObject>(); + chartDto.Select(d => d.HourOfDay).Where(d => d != null).Dump(); + chartDto.Dump(); +} + +// Define other methods and classes here +public class WasteChartDto +{ + public string HoursOfDay { get; set; } + public string HourOfDay { get; set; } + public string DayOfDay { get; set; } + public string DaysOfWeek { get; set; } + + public double Patient25thVolume { get; set; } + public double PatientMedianVolume { get; set; } + public double Patient75thVolume { get; set; } + public double Patient90thVolume { get; set; } + public double Staff25thVolume { get; set; } + public double StaffMedianVolume { get; set; } + public double Staff75thVolume { get; set; } + public double Staff90thVolume { get; set; } + public double OptimalMedianVolume { get; set; } + public double Acuity25thVolume { get; set; } + public double AcuityMedianVolume { get; set; } + public double Acuity75thVolume { get; set; } + + public WasteChartDto() + { + + } + +} \ No newline at end of file diff --git a/test.linq b/test.linq new file mode 100644 index 0000000..bea5b9e --- /dev/null +++ b/test.linq @@ -0,0 +1,301 @@ + + + 77b65bea-e766-4e3c-a1ed-c4c2534b6019 + true + D0001-SQL-11.sdt.local + jazz dev master Prod + true + + <ProgramFilesX64>\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics\Newtonsoft.Json.dll + Amazon.Lambda.S3Events + AWSSDK.Core + AWSSDK.S3 + Amazon + Amazon.Auth.AccessControlPolicy + Amazon.Auth.AccessControlPolicy.ActionIdentifiers + Amazon.Internal + Amazon.Lambda.S3Events + Amazon.MissingTypes + Amazon.Runtime + Amazon.Runtime.CredentialManagement + Amazon.Runtime.CredentialManagement.Internal + Amazon.Runtime.EventStreams + Amazon.Runtime.EventStreams.Internal + Amazon.Runtime.Internal + Amazon.Runtime.Internal.Auth + Amazon.Runtime.Internal.Settings + Amazon.Runtime.Internal.Transform + Amazon.Runtime.Internal.Util + Amazon.Runtime.SharedInterfaces + Amazon.Runtime.SharedInterfaces.Internal + Amazon.S3 + Amazon.S3.Encryption + Amazon.S3.Encryption.Internal + Amazon.S3.Internal + Amazon.S3.IO + Amazon.S3.Model + Amazon.S3.Model.Internal.MarshallTransformations + Amazon.S3.Transfer + Amazon.S3.Util + Amazon.Util + Amazon.Util.Internal + Amazon.Util.Internal.PlatformServices + Newtonsoft.Json + Newtonsoft.Json.Converters + Newtonsoft.Json.Linq + Newtonsoft.Json.Schema + Newtonsoft.Json.Serialization + System + System.Diagnostics + System.Diagnostics.Tracing + System.IO.Compression + ThirdParty.BouncyCastle.Asn1 + ThirdParty.BouncyCastle.Asn1.Utilities + ThirdParty.BouncyCastle.Math + ThirdParty.BouncyCastle.OpenSsl + ThirdParty.BouncyCastle.Utilities.IO.Pem + ThirdParty.Ionic.Zlib + ThirdParty.Json.LitJson + ThirdParty.MD5 + System.ComponentModel + + +private static string tableQuery = @"SELECT c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE +, CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) IsPrimaryKey +FROM INFORMATION_SCHEMA.COLUMNS AS c +LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON tc.TABLE_SCHEMA = c.TABLE_SCHEMA AND tc.TABLE_NAME = c.TABLE_NAME +LEFT OUTER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.TABLE_SCHEMA = tc.TABLE_SCHEMA AND ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME AND ccu.COLUMN_NAME = c.COLUMN_NAME +WHERE c.TABLE_SCHEMA in ('cci', 'dss') +AND (CASE c.TABLE_SCHEMA +WHEN 'cci' THEN 1 +ELSE + CASE WHEN c.TABLE_NAME IN ('DimCaseType', 'CaseTypeFamily', 'CaseTypeFamilyMapping', 'CaseTypeFamilyMappingAPRDRG', 'CaseTypeFamilyMappingICD10', 'CaseTypeFamilyMappingCPT', 'CaseTypeFamilyVersion') + THEN 1 ELSE 0 END END = 1) +AND c.DATA_TYPE NOT IN ('datetime','uniqueidentifier', 'timestamp') +AND NOT (c.COLUMN_NAME = 'RowID' and CAST(CASE WHEN ccu.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END AS BIT) = 1) +AND tc.CONSTRAINT_TYPE = 'Primary Key' +ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION"; + +private List OrderByStatements; +private List ColumnsToBeExcluded; + +void Main() +{ + OrderByStatements = new List + { + new OrderByInformation("cci.InitiativeWorkflowHistory", new [] {"FromStep","ToStep"}), + new OrderByInformation("cci.VariationEncounterSavingInfo", new []{"EncounterRecordNumber","PhysicianID"}), + new OrderByInformation("cci.FactOpportunityMetric", new []{"FiscalYearID","FiscalMonthID"}), + new OrderByInformation("cci.FactOpportunitySavings", new []{"FiscalyYearID","FiscalMonthID"}), + new OrderByInformation("dss.DimCaseType", new []{"Name"}) + }; + ColumnsToBeExcluded = new List + { + new ColumnsToExclude("cci.SystemSetting", new [] {"IsEncrypted"}), + new ColumnsToExclude("cci.Configuration", new [] {"InitiativeIsSimplifiedWorkflow"}) + }; + + var result = GetTables(); + var tableList = result.Select(r => r.SchemaTable); + var sqlStatements = result.Select(r => r.SqlSelect); + // result.Dump(nameof(result)); + // tableList.Dump(nameof(tableList)); + // sqlStatements.Dump(nameof(sqlStatements)); + var connections = new ServerInstance[] { + new ServerInstance("D0001-SQL-11.sdt.local","jazz dev master Prod", tableList), + new ServerInstance("D0001-SQL-11.sdt.local", "jazz tst master prod", tableList) + }.ToList(); + DoTheComparisons(connections, sqlStatements); +} + +// Define other methods and classes here + +#region Gather Table Information + +public IList
GetTables() +{ + return ExecuteQueryDynamic(tableQuery) + .GroupBy(x => new { x.TABLE_SCHEMA, x.TABLE_NAME }, (g, d) => new Table + { + SchemaName = g.TABLE_SCHEMA, + TableName = g.TABLE_NAME, + Columns = d + .Select(y => new Column + { + ColumnName = y.COLUMN_NAME, + DataType = y.DATA_TYPE, + IsPrimaryKey = y.IsPrimaryKey + }), + OrderBy = OrderByStatements?.SingleOrDefault(obs => obs.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.OrderBy, + Exclude = ColumnsToBeExcluded?.SingleOrDefault(ctbe => ctbe.TableName == $"{g.TABLE_SCHEMA}.{g.TABLE_NAME}")?.ColumnNames ?? new List() + }).ToList(); +} + +public class Table +{ + public string SchemaName { get; set; } + public string TableName { get; set; } + public IEnumerable Columns { get; set; } + public IEnumerable OrderBy { get; set; } + public IEnumerable Exclude { get; set; } + internal string SchemaTable => $"{SchemaName}.{TableName}"; + public string SqlSelect => $"select\r\n\t{SelectColumns}\r\nfrom {SchemaTable} OBJ{OrderByStatement}"; + internal string SelectColumns => !Columns?.Any() ?? true ? "*" : string.Join(",\r\n\t", Columns.Where(c => !Exclude.ToList().Contains(c.ColumnName)).Select(c => c.ColumnName)); + internal string OrderByStatement => !OrderBy?.Any() ?? true ? "" : "\r\nOrder By " + string.Join(", ", OrderBy.Select(ob => $"{ob.ColumnName}{(ob.IsDescending ? " DESC" : "")}")); +} + +public class Column +{ + public string ColumnName { get; set; } + public string DataType { get; set; } + public bool IsPrimaryKey { get; set; } +} + +public class OrderBy +{ + public string ColumnName { get; set; } + public bool IsDescending { get; set; } = false; +} + +public class OrderByInformation +{ + public string TableName { get; set; } + public IEnumerable OrderBy { get; set; } + public OrderByInformation(string tableName, IEnumerable columns) + { + TableName = tableName; + OrderBy = columns.Select(c => new OrderBy + { + ColumnName = c.StartsWith("D|") ? c.Substring(2) : c, + IsDescending = c.StartsWith("D|") + }); + } +} + +public class ColumnsToExclude +{ + public string TableName { get; set; } + public IEnumerable ColumnNames { get; set; } + public ColumnsToExclude(string tableName, IEnumerable columns) + { + TableName = tableName; + ColumnNames = columns; + } +} + +#endregion + +#region Do the comparisons + +public void DoTheComparisons(IEnumerable connections, IEnumerable sqlSelects) +{ + + var sql = string.Join("\r\n", sqlSelects); + var dataLegacy = GetData(connections.First(), sql); + var dataUpdate = GetData(connections.Last(), sql); + + foreach (var dt in Enumerable.Range(0, dataLegacy.Tables.Count)) + { + var legacy = dataLegacy.Tables[dt].Rows; + var update = dataUpdate.Tables[dt].Rows; + var idxCount = legacy.Count; + var compare = new List(); + foreach (var row in Enumerable.Range(0, idxCount)) + { + var r = legacy[row]; + if (row < update.Count) + { + var u = update[row]; + var rJson = JsonConvert.SerializeObject(r.ItemArray); + var uJson = JsonConvert.SerializeObject(u.ItemArray); + if (rJson != uJson) + { + compare.Add(new CompareSet(r, u)); + } + } + else + { + compare.Add(new CompareSet(r, null)); + } + } + if (compare.Any()) + { + compare.Dump(dataLegacy.Tables[dt].TableName, 3); + } + else + { + "No differences found in data".Dump(dataLegacy.Tables[dt].TableName); + } + } +} + +public class ServerInstance +{ + public string Server { get; set; } + public string Database { get; set; } + public IEnumerable TableNames { get; set; } + public ServerInstance(string server, string database, IEnumerable tableNames) + { + Server = server; + Database = database; + TableNames = tableNames; + } +} + +public DataSet GetData(ServerInstance serverInstance, string sql) +{ + var server = serverInstance.Server; + var database = serverInstance.Database; + var connStr = $"data source={server};initial catalog='{database}';persist security info=True;Integrated Security=SSPI;"; + using (var conn = new SqlConnection(connStr)) + { + var dataset = new DataSet(); + var adapter = new SqlDataAdapter(sql, conn); + adapter.Fill(dataset); + var tableNames = serverInstance.TableNames; + var idx = 0; + foreach (var tableName in tableNames) + { + dataset.Tables[idx].TableName = tableName; + idx += 1; + } + return dataset; + } +} + +public class CompareSet +{ + internal IList ColumnNames {get;set;} + internal IList Legacy { get; set; } + internal IList Update { get; set; } + public IList Rows {get;set;} + public CompareSet(DataRow right, DataRow left) + { + ColumnNames = right.Table.Columns.Cast().Select(dc => dc.ColumnName).ToList(); + Legacy = right.ItemArray.ToList(); + Update = left?.ItemArray.ToList(); + Rows = ColumnNames.Select((c, i) => new Row(c, Legacy[i], Update?[i])).ToList(); + } + +} + +public class Row +{ + public string Column; + public object Left; + public object Right; + public Row(string column, object left, object right) + { + Column = column; + Left = left; + Right = right; + } + + object ToDump() => new{ + Column = Left.Equals(Right ?? "") ? (object)Column : new XElement("LINQPad.HTML", new XElement("div", new XAttribute("style", "background-color:lightyellow;color:black"), Column)), + Left, + Right, + }; +} + +#endregion diff --git a/webex.exe b/webex.exe new file mode 100644 index 0000000000000000000000000000000000000000..6bbc3b7b9a23834ad92e2886a922228804e6304f GIT binary patch literal 253968 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

>519TV-M7 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�mTg|;PszdO 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 T_wM-pv4oIK3BwP*#W4Q|35Hq2 literal 0 HcmV?d00001 -- 2.54.0