From e5f8e500c125ee233c6f7af5ad0077c0ed6abfcb Mon Sep 17 00:00:00 2001 From: Mihajlo Medjedovic Date: Fri, 6 Jun 2025 15:03:36 +0200 Subject: [PATCH 01/14] fix: reload startupservice after user approves the MPE_TABLES page --- .../app/models/sas/editors-stagedata.model.ts | 16 ----------- .../models/sas/public-getchangeinfo.model.ts | 28 +++++++++++++++++++ .../approve-details.component.ts | 12 +++++++- client/src/app/services/sas.service.ts | 4 +++ 4 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 client/src/app/models/sas/public-getchangeinfo.model.ts diff --git a/client/src/app/models/sas/editors-stagedata.model.ts b/client/src/app/models/sas/editors-stagedata.model.ts index 70794fd..d5d831e 100644 --- a/client/src/app/models/sas/editors-stagedata.model.ts +++ b/client/src/app/models/sas/editors-stagedata.model.ts @@ -1,30 +1,14 @@ import { BaseSASResponse } from './common/BaseSASResponse' export interface EditorsStageDataSASResponse extends BaseSASResponse { - SYSDATE: string - SYSTIME: string sasparams: Sasparam[] - _DEBUG: string - _PROGRAM: string AUTOEXEC: string - MF_GETUSER: string - SYSCC: string SYSENCODING: string - SYSERRORTEXT: string SYSHOSTINFOLONG: string - SYSHOSTNAME: string SYSPROCESSID: string SYSPROCESSMODE: string SYSPROCESSNAME: string - SYSJOBID: string - SYSSCPL: string - SYSSITE: string SYSTCPIPHOSTNAME: string - SYSUSERID: string - SYSVLONG: string - SYSWARNINGTEXT: string - END_DTTM: string - MEMSIZE: string } export interface Sasparam { diff --git a/client/src/app/models/sas/public-getchangeinfo.model.ts b/client/src/app/models/sas/public-getchangeinfo.model.ts new file mode 100644 index 0000000..9748d85 --- /dev/null +++ b/client/src/app/models/sas/public-getchangeinfo.model.ts @@ -0,0 +1,28 @@ +import { BaseSASResponse } from "./common/BaseSASResponse"; + +export interface PublicGetChangeinfo extends BaseSASResponse { + jsparams: Jsparam[] +} + +export interface Jsparam { + TABLE_ID: string; + SUBMIT_STATUS_CD: string; + BASE_LIB: string; + BASE_DS: string; + SUBMITTED_BY_NM: string; + SUBMITTED_ON: number; + SUBMITTED_REASON_TXT: string; + INPUT_OBS: number; + INPUT_VARS: number; + NUM_OF_APPROVALS_REQUIRED: number; + NUM_OF_APPROVALS_REMAINING: number; + REVIEWED_BY_NM: string; + REVIEWED_ON?: any; + TABLE_NM: string; + BASE_TABLE: string; + REVIEWED_ON_DTTM: string; + SUBMITTED_ON_DTTM: string; + LIB_ENGINE: string; + ALLOW_RESTORE: string; + REASON: string; +} \ No newline at end of file diff --git a/client/src/app/review/approve-details/approve-details.component.ts b/client/src/app/review/approve-details/approve-details.component.ts index c0e6639..020072f 100644 --- a/client/src/app/review/approve-details/approve-details.component.ts +++ b/client/src/app/review/approve-details/approve-details.component.ts @@ -13,6 +13,8 @@ import { AuditorsPostdataSASResponse, Param } from '../../models/sas/auditors-postdata.model' +import { PublicGetChangeinfo } from 'src/app/models/sas/public-getchangeinfo.model' +import { SasService } from 'src/app/services' interface ChangesObj { ind: any @@ -76,9 +78,11 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy { public diffsLimit: boolean = false public recordsLimit: number = 100 + public refreshStartupserviceAfterApprove: boolean = false constructor( private sasStoreService: SasStoreService, + private sasService: SasService, private eventService: EventService, private router: ActivatedRoute, private route: Router @@ -162,6 +166,8 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy { await this.sasStoreService .approveTable(approveParams, 'SASControlTable', 'auditors/postdata') .then((res: any) => { + // If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables + if (this.refreshStartupserviceAfterApprove) this.sasService.reloadStartupData() this.route.navigateByUrl('/review/history') }) .catch((err: any) => { @@ -176,7 +182,7 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy { public async callChangesInfo(tableId: any) { await this.sasStoreService .getChangeInfo(tableId) - .then((res: any) => { + .then((res: PublicGetChangeinfo) => { this.tableDetails = res.jsparams[0] this.jsParams = res.jsparams[0] @@ -189,6 +195,10 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy { } this.keysArray = keysArray + + // If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables + // After user approved if armed, reload will be triggered + if (res.jsparams[0].BASE_DS === 'MPE_TABLES') this.refreshStartupserviceAfterApprove = true }) .catch((err: any) => { this.acceptLoading = false diff --git a/client/src/app/services/sas.service.ts b/client/src/app/services/sas.service.ts index 5c596b8..782c38a 100644 --- a/client/src/app/services/sas.service.ts +++ b/client/src/app/services/sas.service.ts @@ -333,6 +333,10 @@ export class SasService { }) } + public reloadStartupData() { + this.loadStartupServiceEmitter.emit() + } + public getLicenseSiteId(): string[] { return this.license_site_id.value || [] } From 4f2c993b2d5122a061d1d4a5ae7a63c38766153f Mon Sep 17 00:00:00 2001 From: Mihajlo Medjedovic Date: Fri, 6 Jun 2025 15:03:51 +0200 Subject: [PATCH 02/14] style: lint --- .../models/sas/public-getchangeinfo.model.ts | 46 +++++++++---------- .../approve-details.component.ts | 6 ++- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/client/src/app/models/sas/public-getchangeinfo.model.ts b/client/src/app/models/sas/public-getchangeinfo.model.ts index 9748d85..0ea9815 100644 --- a/client/src/app/models/sas/public-getchangeinfo.model.ts +++ b/client/src/app/models/sas/public-getchangeinfo.model.ts @@ -1,28 +1,28 @@ -import { BaseSASResponse } from "./common/BaseSASResponse"; +import { BaseSASResponse } from './common/BaseSASResponse' export interface PublicGetChangeinfo extends BaseSASResponse { - jsparams: Jsparam[] + jsparams: Jsparam[] } export interface Jsparam { - TABLE_ID: string; - SUBMIT_STATUS_CD: string; - BASE_LIB: string; - BASE_DS: string; - SUBMITTED_BY_NM: string; - SUBMITTED_ON: number; - SUBMITTED_REASON_TXT: string; - INPUT_OBS: number; - INPUT_VARS: number; - NUM_OF_APPROVALS_REQUIRED: number; - NUM_OF_APPROVALS_REMAINING: number; - REVIEWED_BY_NM: string; - REVIEWED_ON?: any; - TABLE_NM: string; - BASE_TABLE: string; - REVIEWED_ON_DTTM: string; - SUBMITTED_ON_DTTM: string; - LIB_ENGINE: string; - ALLOW_RESTORE: string; - REASON: string; -} \ No newline at end of file + TABLE_ID: string + SUBMIT_STATUS_CD: string + BASE_LIB: string + BASE_DS: string + SUBMITTED_BY_NM: string + SUBMITTED_ON: number + SUBMITTED_REASON_TXT: string + INPUT_OBS: number + INPUT_VARS: number + NUM_OF_APPROVALS_REQUIRED: number + NUM_OF_APPROVALS_REMAINING: number + REVIEWED_BY_NM: string + REVIEWED_ON?: any + TABLE_NM: string + BASE_TABLE: string + REVIEWED_ON_DTTM: string + SUBMITTED_ON_DTTM: string + LIB_ENGINE: string + ALLOW_RESTORE: string + REASON: string +} diff --git a/client/src/app/review/approve-details/approve-details.component.ts b/client/src/app/review/approve-details/approve-details.component.ts index 020072f..5c46293 100644 --- a/client/src/app/review/approve-details/approve-details.component.ts +++ b/client/src/app/review/approve-details/approve-details.component.ts @@ -167,7 +167,8 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy { .approveTable(approveParams, 'SASControlTable', 'auditors/postdata') .then((res: any) => { // If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables - if (this.refreshStartupserviceAfterApprove) this.sasService.reloadStartupData() + if (this.refreshStartupserviceAfterApprove) + this.sasService.reloadStartupData() this.route.navigateByUrl('/review/history') }) .catch((err: any) => { @@ -198,7 +199,8 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy { // If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables // After user approved if armed, reload will be triggered - if (res.jsparams[0].BASE_DS === 'MPE_TABLES') this.refreshStartupserviceAfterApprove = true + if (res.jsparams[0].BASE_DS === 'MPE_TABLES') + this.refreshStartupserviceAfterApprove = true }) .catch((err: any) => { this.acceptLoading = false From 24545f2acdd5bd73cbe062526f2bd043269cc6a3 Mon Sep 17 00:00:00 2001 From: allan Date: Fri, 6 Jun 2025 21:05:08 +0100 Subject: [PATCH 03/14] fix: ensuring apploc is not case sensitive. Closes #171 --- sas/package-lock.json | 8 ++++---- sas/package.json | 2 +- sas/sasjs/utils/buildinitviya.sas | 11 ++++++++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/sas/package-lock.json b/sas/package-lock.json index d296fab..94c1edd 100644 --- a/sas/package-lock.json +++ b/sas/package-lock.json @@ -7,7 +7,7 @@ "name": "dc-sas", "dependencies": { "@sasjs/cli": "^4.12.7", - "@sasjs/core": "^4.58.2" + "@sasjs/core": "^4.59.0" } }, "node_modules/@coolaj86/urequest": { @@ -83,9 +83,9 @@ "license": "MIT" }, "node_modules/@sasjs/core": { - "version": "4.58.2", - "resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.58.2.tgz", - "integrity": "sha512-P/DMCHfFrZT+50DIT7CiYBSjxOo5m0AHBLNKHGFOMfQnEymOKekQPk2Xzw5wkQyg8gjp2yBKhRwhpni5rvJFgQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.59.0.tgz", + "integrity": "sha512-mv7UU3Nc9J4Q0h+QerN2DkZDIKNwOG6dg+w55hjpl9qyncKqn0YKk3fc9P/P+F8FB9D6VMUFDy3AgAUHXMjZ8A==", "license": "MIT" }, "node_modules/@sasjs/lint": { diff --git a/sas/package.json b/sas/package.json index 5637701..7bf2508 100644 --- a/sas/package.json +++ b/sas/package.json @@ -29,6 +29,6 @@ "private": true, "dependencies": { "@sasjs/cli": "^4.12.7", - "@sasjs/core": "^4.58.2" + "@sasjs/core": "^4.59.0" } } diff --git a/sas/sasjs/utils/buildinitviya.sas b/sas/sasjs/utils/buildinitviya.sas index 409e4f9..04d1833 100644 --- a/sas/sasjs/utils/buildinitviya.sas +++ b/sas/sasjs/utils/buildinitviya.sas @@ -2,6 +2,11 @@ @file buildinitviya.sas @brief initialisation for viya build program +

SAS Macros

+ @li mfv_getfolderpath.sas + @li mfv_getpathuri.sas + @li mv_createfolder.sas + **/ options nonotes nomprint; @@ -9,4 +14,8 @@ options nonotes nomprint; /* update apploc to default to user home area if not set */ %let apploc=%sysfunc(ifc("&apploc"="/Public/app/dcplaceholder" ,/Users/&sysuserid/My Folder/Data Controller - ,&apploc)); \ No newline at end of file + ,&apploc)); + +/* ensure the correct casing of appLoc */ +%mv_createfolder(path=&apploc) +%let apploc=%mfv_getfolderpath(%mfv_getpathuri(&apploc)); \ No newline at end of file From 2011c2eee7340fa787e46581890f4d8f93035dc8 Mon Sep 17 00:00:00 2001 From: allan Date: Fri, 6 Jun 2025 23:23:47 +0100 Subject: [PATCH 04/14] chore(docs): updating README with viya deploy details --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cf698e4..c4eed5f 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,16 @@ _Problems with the above include:_ Data Controller for SAS® solves all these issues in a simple-to-install, user-friendly, secure, documented, battle-tested web application. Available on Viya, SAS 9 EBI, and [SASjs Server](https://server.sasjs.io). -For more information: +An individual Viya deploy can be done in just 2 lines of #SAS code! + +```sas +filename dc url "https://git.datacontroller.io/dc/dc/releases/download/latest/viya_noweb.sas"; +%inc dc; +``` + +For a multi-user deploy, using a shared system account, please see [deploy docs](https://docs.datacontroller.io/deploy-viya/). + +For further information: * Main site: https://datacontroller.io * Docs: https://docs.datacontroller.io From 063c90caf4acf5fc3632508600239c828d72dab8 Mon Sep 17 00:00:00 2001 From: allan Date: Fri, 6 Jun 2025 23:24:35 +0100 Subject: [PATCH 05/14] chore(docs): readme fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4eed5f..2d2f65d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Data Controller for SAS® solves all these issues in a simple-to-install, user-f An individual Viya deploy can be done in just 2 lines of #SAS code! ```sas -filename dc url "https://git.datacontroller.io/dc/dc/releases/download/latest/viya_noweb.sas"; +filename dc url "https://git.datacontroller.io/dc/dc/releases/download/latest/viya.sas"; %inc dc; ``` From f6d7d6f90c978ac8c071471dfb67a60834424de5 Mon Sep 17 00:00:00 2001 From: allan Date: Tue, 10 Jun 2025 09:41:18 +0100 Subject: [PATCH 06/14] fix: export unregistered formats Closes #158 --- sas/package-lock.json | 8 +- sas/package.json | 2 +- sas/sasjs/sasjsconfig.json | 73 ++++--------------- sas/sasjs/services/public/getrawdata.sas | 3 + sas/sasjs/services/public/getrawdata.test.sas | 34 +++++++++ sas/sasjs/tests/testinit.sas | 2 +- sas/sasjs/tests/testsetup.sas | 12 ++- 7 files changed, 68 insertions(+), 66 deletions(-) diff --git a/sas/package-lock.json b/sas/package-lock.json index 94c1edd..3d957be 100644 --- a/sas/package-lock.json +++ b/sas/package-lock.json @@ -7,7 +7,7 @@ "name": "dc-sas", "dependencies": { "@sasjs/cli": "^4.12.7", - "@sasjs/core": "^4.59.0" + "@sasjs/core": "^4.59.1" } }, "node_modules/@coolaj86/urequest": { @@ -83,9 +83,9 @@ "license": "MIT" }, "node_modules/@sasjs/core": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.59.0.tgz", - "integrity": "sha512-mv7UU3Nc9J4Q0h+QerN2DkZDIKNwOG6dg+w55hjpl9qyncKqn0YKk3fc9P/P+F8FB9D6VMUFDy3AgAUHXMjZ8A==", + "version": "4.59.1", + "resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.59.1.tgz", + "integrity": "sha512-52GNI4nIll5YivI8uobWrucE6TkHcTjcbKTr/YPC9eTauC4sh0V0MptebfAJ5E6vE5P2WevNZGr42KdDpckLpg==", "license": "MIT" }, "node_modules/@sasjs/lint": { diff --git a/sas/package.json b/sas/package.json index 7bf2508..4c29ace 100644 --- a/sas/package.json +++ b/sas/package.json @@ -29,6 +29,6 @@ "private": true, "dependencies": { "@sasjs/cli": "^4.12.7", - "@sasjs/core": "^4.59.0" + "@sasjs/core": "^4.59.1" } } diff --git a/sas/sasjs/sasjsconfig.json b/sas/sasjs/sasjsconfig.json index 1161b8f..4d5067d 100644 --- a/sas/sasjs/sasjsconfig.json +++ b/sas/sasjs/sasjsconfig.json @@ -94,38 +94,41 @@ }, { "name": "viya", - "serverUrl": "https://sas.4gl.io", + "serverUrl": "https://viya-f0g8ht62vq.engage.sas.com", "serverType": "SASVIYA", "httpsAgentOptions": { "allowInsecureRequests": false }, "appLoc": "/Public/app/dcplaceholder", + "deployConfig": { + "deployServicePack": true, + "deployScripts": [ + "sasjs/utils/viyadeploy.sh" + ] + }, "macroFolders": [ "sasjs/targets/viya/macros_viya" ], "programFolders": [ "sasjs/db/datactrl" ], - "binaryFolders": [], "buildConfig": { "initProgram": "sasjs/utils/buildinitviya.sas", "buildResultsFolder": "sasjsresults", "buildOutputFolder": "sasjsbuild", - "buildOutputFileName": "viya.sas" + "buildOutputFileName": "viya.sas", + "termProgram": "", + "macroVars": {} }, "serviceConfig": { - "initProgram": "sasjs/utils/serviceinitviya.sas", "serviceFolders": [ "sasjs/targets/viya/services_viya/viya_users", "sasjs/targets/viya/services_viya/admin", "sasjs/targets/viya/services_viya/public" - ] - }, - "deployConfig": { - "deployServicePack": true, - "deployScripts": [ - "sasjs/utils/viyadeploy.sh" - ] + ], + "initProgram": "sasjs/utils/serviceinitviya.sas", + "termProgram": "", + "macroVars": {} }, "streamConfig": { "streamWeb": true, @@ -137,54 +140,6 @@ }, "contextName": "SAS Job Execution compute context" }, - { - "name": "viyacloud", - "serverUrl": "https://4gl.viyacloud.sas.com", - "serverType": "SASVIYA", - "httpsAgentOptions": { - "rejectUnauthorized": false, - "allowInsecureRequests": true - }, - "appLoc": "/30.SASApps/app/dc", - "macroFolders": [ - "sasjs/targets/viya/macros_viya" - ], - "programFolders": [ - "sasjs/db/datactrl" - ], - "buildConfig": { - "initProgram": "sasjs/utils/buildinitviya.sas", - "termProgram": "sasjs/utils/buildtermviya.sas", - "macroVars": { - "dcpath": "/opt/sas/viya/config/var/tmp/dc", - "adminGroup": "DataBuilders" - }, - "buildResultsFolder": "sasjsresults", - "buildOutputFolder": "sasjsbuild", - "buildOutputFileName": "viya.sas" - }, - "serviceConfig": { - "initProgram": "sasjs/utils/serviceinitviya.sas", - "serviceFolders": [ - "sasjs/targets/viya/services_viya/viya_users", - "sasjs/targets/viya/services_viya/admin", - "sasjs/targets/viya/services_viya/public" - ], - "termProgram": "", - "macroVars": {} - }, - "streamConfig": { - "streamWeb": true, - "streamWebFolder": "webv", - "webSourcePath": "../client/dist", - "streamServiceName": "clickme", - "assetPaths": [] - }, - "deployConfig": { - "deployServicePack": true - }, - "contextName": "Datacontroller compute context" - }, { "name": "vtest", "appLoc": "/30.SASApps/app/vtest", diff --git a/sas/sasjs/services/public/getrawdata.sas b/sas/sasjs/services/public/getrawdata.sas index 158568c..1656c0e 100644 --- a/sas/sasjs/services/public/getrawdata.sas +++ b/sas/sasjs/services/public/getrawdata.sas @@ -54,7 +54,10 @@ data _null_; /* if a TXTEMPORAL table then filter as such */ call symputx('txfrom',var_txfrom); call symputx('txto',var_txto); +run; +/* if a format, extract relevant info */ +data _null_; ds=symget('ds'); is_fmt=0; if subpad(cats(reverse(ds)),1,3)=:'CF-' then do; diff --git a/sas/sasjs/services/public/getrawdata.test.sas b/sas/sasjs/services/public/getrawdata.test.sas index becdbd8..7f294fc 100644 --- a/sas/sasjs/services/public/getrawdata.test.sas +++ b/sas/sasjs/services/public/getrawdata.test.sas @@ -76,3 +76,37 @@ run; test=EQUALS 3, outds=work.test_results ) + +/* test 3 - when there is a format catalog / nothing else in the library */ +data work.params3; + length name $32 value $1000; + name='type';value='SAS';output; + name='table';value="FMTONLY.DCFMTS-FC";output; + name='filter';value='0';output; +run; + +%mx_testservice(&_program, + viyacontext=&defaultcontext, + inputparams=work.params3, + outref=web3, + viyaresult=WEBOUT_TXT +) + +data work.results3; + infile web3; + input; + putlog _infile_; + if _infile_=:'datalines4;' then do; + output; + output; + output; + stop; + end; + if _n_>100 then stop; +run; + +%mp_assertdsobs(work.results3, + desc=datalines file is successfully returned for LONE format catalog, + test=EQUALS 3, + outds=work.test_results +) diff --git a/sas/sasjs/tests/testinit.sas b/sas/sasjs/tests/testinit.sas index d4beb8e..1bdd049 100644 --- a/sas/sasjs/tests/testinit.sas +++ b/sas/sasjs/tests/testinit.sas @@ -21,7 +21,7 @@ REMOVE THAT LAST MACRO %let syscc=0; %global apploc _program dclib defaultcontext _debug sasjs_mdebug dc_dttmtfmt; -%let defaultcontext=Datacontroller compute context; +%let defaultcontext=SAS Job Execution compute context; %let sasjs_mdebug=0; options mprint mprintnest nobomfile lrecl=32767; diff --git a/sas/sasjs/tests/testsetup.sas b/sas/sasjs/tests/testsetup.sas index dd9df5c..4d15056 100644 --- a/sas/sasjs/tests/testsetup.sas +++ b/sas/sasjs/tests/testsetup.sas @@ -28,7 +28,7 @@ %global apploc _program; -%let defaultcontext=Datacontroller compute context; +%let defaultcontext=SAS Job Execution compute context; data _null_; length _pgm $1000; @@ -60,6 +60,9 @@ run; %let testloc=%sysfunc(pathname(&DC_LIBREF))/fmt%mf_getuniquefileref(); %mf_mkdir(&testloc) libname dctest "&testloc"; +/* test library with only one format catalog */ +%mf_mkdir(&testloc/fmtonly) +libname fmtonly "&testloc/fmtonly"; /* add formats */ PROC FORMAT library=dctest.dcfmts; @@ -99,6 +102,10 @@ run; proc append base=&dc_libref..mpe_tables data=work.append; run; +/* lone format catalog */ +proc format cntlin=work.fmts library=fmtonly.dcfmts; +run; + /* add some other tables */ %mp_coretable(LOCKTABLE,libds=dctest.locktable) %mp_coretable(DIFFTABLE,libds=dctest.difftable) @@ -130,6 +137,7 @@ options mprint; put _infile_; if last then do; put "libname dctest '&testloc';"; + put "libname fmtonly '&testloc/fmtonly';"; end; run; data _null_; @@ -151,6 +159,7 @@ options mprint; put _infile_; if last then do; put "libname dctest '&testloc';"; + put "libname fmtonly '&testloc/fmtonly';"; end; run; %ms_deletefile(&root/services/public/settings.sas) @@ -182,6 +191,7 @@ options mprint; put _infile_; if last then do; put "libname dctest '&testloc';"; + put "libname fmtonly '&testloc/fmtonly';"; end; run; %mm_deletestp(target=&root/services/public/Data_Controller_Settings) From e4dbab8b1654b24e610e4b0603d1cf2b02a451e2 Mon Sep 17 00:00:00 2001 From: allan Date: Tue, 10 Jun 2025 16:18:30 +0100 Subject: [PATCH 07/14] feat: adding 4 new tables for catalogs --- sas/package-lock.json | 24 +++---- sas/package.json | 2 +- .../db/datactrl/mpe_datacatalog_cats.ddl | 17 +++++ .../db/datactrl/mpe_datacatalog_objs.ddl | 21 ++++++ sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl | 20 ++++++ sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl | 22 +++++++ sas/sasjs/macros/mpe_makedatamodel.sas | 66 ++++++++++++++++++- sas/sasjs/macros/mpe_makedatamodel.test.sas | 26 ++++++++ sas/sasjs/macros/mpe_refreshtables.sas | 2 +- sas/sasjs/macros/mpe_refreshtables.test.sas | 49 ++++++++++++++ .../viya/macros_viya/dc_refreshcatalog.sas | 30 +++++---- 11 files changed, 250 insertions(+), 29 deletions(-) create mode 100644 sas/sasjs/db/datactrl/mpe_datacatalog_cats.ddl create mode 100644 sas/sasjs/db/datactrl/mpe_datacatalog_objs.ddl create mode 100644 sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl create mode 100644 sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl create mode 100644 sas/sasjs/macros/mpe_makedatamodel.test.sas create mode 100644 sas/sasjs/macros/mpe_refreshtables.test.sas diff --git a/sas/package-lock.json b/sas/package-lock.json index 3d957be..d01abbc 100644 --- a/sas/package-lock.json +++ b/sas/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "dc-sas", "dependencies": { - "@sasjs/cli": "^4.12.7", + "@sasjs/cli": "^4.12.8", "@sasjs/core": "^4.59.1" } }, @@ -30,9 +30,9 @@ } }, "node_modules/@sasjs/adapter": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.11.3.tgz", - "integrity": "sha512-KF6G4vzs4l4efjpCD02og3kB44uFfJ1u2UWu749VdHtLKNN9l+PO26/moR+YAmRmmz2I9sC3X09fZE1nlN6zgw==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.12.1.tgz", + "integrity": "sha512-0217oZIkrecOyQygRe6Azgc1C4TIcjB5noi15fU4Rd5GsfDpleKVfQQdzYZ7im/vesWlLIVl/yUT67MMaQe0ew==", "hasInstallScript": true, "license": "ISC", "dependencies": { @@ -45,14 +45,14 @@ } }, "node_modules/@sasjs/cli": { - "version": "4.12.7", - "resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.12.7.tgz", - "integrity": "sha512-KcXSR+3dRgINOLiN+7oJbzWsNQu7qm1YQ7eaVqiHTZI429BSgZez9+7p1bq09R4otHN8IzMAgLP9se/r9p9yJA==", + "version": "4.12.8", + "resolved": "https://registry.npmjs.org/@sasjs/cli/-/cli-4.12.8.tgz", + "integrity": "sha512-20WiywlcLV22T1XfkAumV66mM3PfQ1N9ihJfpxoOVCFs2wF/ZertqnP4BZ5CE1dc30M1C2oDOzzSSVZqePPQnw==", "hasInstallScript": true, "license": "ISC", "dependencies": { - "@sasjs/adapter": "4.11.3", - "@sasjs/core": "4.58.1", + "@sasjs/adapter": "4.12.1", + "@sasjs/core": "4.59.1", "@sasjs/lint": "2.4.3", "@sasjs/utils": "3.5.2", "adm-zip": "0.5.10", @@ -76,12 +76,6 @@ "sasjs": "build/index.js" } }, - "node_modules/@sasjs/cli/node_modules/@sasjs/core": { - "version": "4.58.1", - "resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.58.1.tgz", - "integrity": "sha512-Qp6KAtp1VZcmN5HLGSIUE9H41qpFuihWLbjNygOYp+NRs/Y8VagpHrYeyIQbh3cSgchiJEMXudLql8hoU06wpg==", - "license": "MIT" - }, "node_modules/@sasjs/core": { "version": "4.59.1", "resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.59.1.tgz", diff --git a/sas/package.json b/sas/package.json index 4c29ace..99ad2d1 100644 --- a/sas/package.json +++ b/sas/package.json @@ -28,7 +28,7 @@ }, "private": true, "dependencies": { - "@sasjs/cli": "^4.12.7", + "@sasjs/cli": "^4.12.8", "@sasjs/core": "^4.59.1" } } diff --git a/sas/sasjs/db/datactrl/mpe_datacatalog_cats.ddl b/sas/sasjs/db/datactrl/mpe_datacatalog_cats.ddl new file mode 100644 index 0000000..9da6250 --- /dev/null +++ b/sas/sasjs/db/datactrl/mpe_datacatalog_cats.ddl @@ -0,0 +1,17 @@ +/** + @file mpe_datacatalog_CATS.ddl + @brief ddl file + @details + + @version 9.3 + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd +**/ + +create table &curlib..mpe_datacatalog_CATS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + constraint pk_mpe_datacatalog_CATS + primary key(libref,memname,tx_to)); diff --git a/sas/sasjs/db/datactrl/mpe_datacatalog_objs.ddl b/sas/sasjs/db/datactrl/mpe_datacatalog_objs.ddl new file mode 100644 index 0000000..c3eff58 --- /dev/null +++ b/sas/sasjs/db/datactrl/mpe_datacatalog_objs.ddl @@ -0,0 +1,21 @@ +/** + @file mpe_datacatalog_CATS.ddl + @brief ddl file + @details + + @version 9.3 + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd +**/ + +create table &curlib..mpe_datacatalog_OBJS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + objname char(32) label='Object Name', + objtype char(8) label='Object Type', + objdesc char(256) label='Object Description', + alias char(32) label='Object Alias', + constraint pk_mpe_datacatalog_OBJS + primary key(libref,memname,objname,objtype,tx_to)); diff --git a/sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl b/sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl new file mode 100644 index 0000000..1d223a0 --- /dev/null +++ b/sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl @@ -0,0 +1,20 @@ +/** + @file mpe_datacatalog_CATS.ddl + @brief ddl file + @details + + @version 9.3 + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd +**/ + +create table &curlib..mpe_datastatus_CATS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + nobjs num label='Number of objects', + created num format=DATETIME. informat=DATETIME. label='Date Created', + modified num format=DATETIME. informat=DATETIME. label='Date Modified', + constraint pk_mpe_datastatus_CATS + primary key(libref,memname,tx_to)); diff --git a/sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl b/sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl new file mode 100644 index 0000000..ec8009b --- /dev/null +++ b/sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl @@ -0,0 +1,22 @@ +/** + @file mpe_datacatalog_CATS.ddl + @brief ddl file + @details + + @version 9.3 + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd +**/ + +create table &curlib..mpe_datastatus_OBJS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + objname char(32) label='Object Name', + objtype char(8) label='Object Type', + created num format=DATETIME. informat=DATETIME. label='Date Created', + modified num format=DATETIME. informat=DATETIME. label='Date Modified', + level num label='Library Concatenation Level', + constraint pk_mpe_datastatus_OBJS + primary key(libref,memname,objname,objtype,tx_to)); diff --git a/sas/sasjs/macros/mpe_makedatamodel.sas b/sas/sasjs/macros/mpe_makedatamodel.sas index 87595ca..084e7e5 100644 --- a/sas/sasjs/macros/mpe_makedatamodel.sas +++ b/sas/sasjs/macros/mpe_makedatamodel.sas @@ -106,6 +106,19 @@ proc datasets lib=&lib noprint; /nomiss unique; quit; proc sql; +create table &lib..mpe_datacatalog_CATS( + TX_FROM float ¬null format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name' +);quit; +proc datasets lib=&lib noprint; + modify mpe_datacatalog_CATS; + index create + pk_mpe_datacatalog_CATS=(tx_to libref memname) + /nomiss unique; +quit; +proc sql; create table &lib..mpe_datacatalog_libs( TX_FROM num ¬null format=datetime19.3, TX_TO num ¬null format=datetime19.3, @@ -125,6 +138,23 @@ proc datasets lib=&lib noprint; /nomiss unique; quit; proc sql; +create table &lib..mpe_datacatalog_OBJS( + TX_FROM num ¬null format=datetime19., + TX_TO num ¬null format=datetime19., + libref char(8) ¬null label='Library Name', + memname char(64) ¬null label='Member Name', + objname char(32) ¬null label='Object Name', + objtype char(8) ¬null label='Object Type', + objdesc char(256) label='Object Description', + alias char(32) label='Object Alias' +);quit; +proc datasets lib=&lib noprint; + modify mpe_datacatalog_OBJS; + index create + pk_mpe_datacatalog_OBJS=(libref memname objname objtype tx_to) + /nomiss unique; +quit; +proc sql; create table &lib..mpe_datacatalog_TABS( TX_FROM num ¬null format=datetime19.3, TX_TO num ¬null format=datetime19.3, @@ -137,7 +167,7 @@ create table &lib..mpe_datacatalog_TABS( nvar num label='Number of Variables', compress char(8) label='Compression Routine', pk_fields char(512) - label='Primary Key Fields (identified by being in a constraint that is both Unique and Not Null)' + label='Primary Key Fields - in a constraint being both Unique and Not Null' );quit; proc datasets lib=&lib noprint; modify mpe_datacatalog_TABS; @@ -169,6 +199,22 @@ proc datasets lib=&lib noprint; /nomiss unique; quit; proc sql; +create table &lib..mpe_datastatus_CATS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + nobjs num ¬null label='Number of objects', + created num ¬null format=DATETIME. label='Date Created', + modified num format=DATETIME. label='Date Modified' +);quit; +proc datasets lib=&lib noprint; + modify mpe_datastatus_CATS; + index create + pk_mpe_datastatus_cats=(libref memname tx_to) + /nomiss unique; +quit; +proc sql; create table &lib..mpe_datastatus_libs( TX_FROM num ¬null format=datetime19.3, TX_TO num ¬null format=datetime19.3, @@ -183,6 +229,24 @@ proc datasets lib=&lib noprint; /nomiss unique; quit; proc sql; +create table &lib..mpe_datastatus_OBJS( + TX_FROM float ¬null format=datetime19., + TX_TO float ¬null format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + objname char(32) label='Object Name', + objtype char(8) label='Object Type', + created num ¬null format=DATETIME. label='Date Created', + modified num format=DATETIME. label='Date Modified', + level num label='Library Concatenation Level' +);quit; +proc datasets lib=&lib noprint; + modify mpe_datastatus_OBJS; + index create + pk_mpe_datastatus_OBJS=(libref memname objname objtype tx_to) + /nomiss unique; +quit; +proc sql; create table &lib..mpe_datastatus_tabs( TX_FROM num ¬null format=datetime19.3, TX_TO num ¬null format=datetime19.3, diff --git a/sas/sasjs/macros/mpe_makedatamodel.test.sas b/sas/sasjs/macros/mpe_makedatamodel.test.sas new file mode 100644 index 0000000..21599e2 --- /dev/null +++ b/sas/sasjs/macros/mpe_makedatamodel.test.sas @@ -0,0 +1,26 @@ +/** + @file + @brief Testing mpe_refreshtables macro + +

SAS Macros

+ @li mpe_makedatamodel.sas + @li mp_assert.sas + @li mp_assertscope.sas + + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd. This code may only be used within Data Controller + and may not be re-distributed or re-sold without the express permission of + 4GL Apps Ltd. + +**/ + +%mp_assertscope(SNAPSHOT) +%mpe_makedatamodel(lib=WORK) +%mp_assertscope(COMPARE, + desc=Checking macro variables against previous snapshot +) + +%mp_assert( + iftrue=(&syscc = 0), + desc=Checking error condition +) \ No newline at end of file diff --git a/sas/sasjs/macros/mpe_refreshtables.sas b/sas/sasjs/macros/mpe_refreshtables.sas index f19d515..c75d820 100644 --- a/sas/sasjs/macros/mpe_refreshtables.sas +++ b/sas/sasjs/macros/mpe_refreshtables.sas @@ -295,7 +295,7 @@ proc sql; %if &ds ne #ALL %then %do; and upcase(memname)="&ds" %end; - ; + ; %end; %bitemporal_dataloader(base_lib=&mpelib diff --git a/sas/sasjs/macros/mpe_refreshtables.test.sas b/sas/sasjs/macros/mpe_refreshtables.test.sas new file mode 100644 index 0000000..ba28673 --- /dev/null +++ b/sas/sasjs/macros/mpe_refreshtables.test.sas @@ -0,0 +1,49 @@ +/** + @file + @brief Testing mpe_refreshtables macro + +

SAS Macros

+ @li mpe_refreshtables.sas + @li mp_assert.sas + @li mp_assertscope.sas + + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd. This code may only be used within Data Controller + and may not be re-distributed or re-sold without the express permission of + 4GL Apps Ltd. + +**/ + +%mp_assertscope(SNAPSHOT) +%mpe_refreshtables(FMTONLY) +%mp_assertscope(COMPARE, + desc=Checking macro variables against previous snapshot +) + +/* make sure that the process picks up a library that contains only a single + catalog */ +proc sql; +create table work.libinfo as + select a.engine, + a.libname, + a.paths, + a.perms, + a.owners, + a.schemas, + a.libid, + b.libsize, + b.table_cnt + from &mpelib..mpe_datacatalog_libs(where=(&dc_dttmtfmt. lt tx_to)) a + left join &mpelib..mpe_datastatus_libs(where=(&dc_dttmtfmt. lt tx_to)) b + on a.libref=b.libref + where a.libref="&libref"; + +%let test1=0; +data _null_; + set work.libinfo; + call symputx('test1',table_cnt); +run; +%mp_assert( + iftrue=(&test1>0), + desc=Checking fmtonly.dcfmts was picked up +) \ No newline at end of file diff --git a/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas b/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas index 196a092..f984e43 100644 --- a/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas +++ b/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas @@ -19,19 +19,27 @@ 4GL Apps Ltd. **/ -%macro dc_refreshcatalog(); +%macro dc_refreshcatalog(libref); %mpe_refreshlibs() -filename executor catalog 'work.code.code.source'; -data libraries; - set &mpelib..mpe_datacatalog_libs; - where &dc_dttmtfmt. le TX_TO; - file executor; - str=cats('%mpe_refreshtables(',libref,')'); - put str; - putlog str; -run; -%inc executor; +%if #&libref# ne ## %then %do; + %put &sysmacroname: assigning specific libref, &libref; + %dc_assignlib(WRITE,&libref) /* write just in order to assign direct lib */ + %mpe_refreshlibs(lib=&libref) + %mpe_refreshtables(&libref) +%end; +%else %do; + filename executor catalog 'work.code.code.source'; + data libraries; + set &mpelib..mpe_datacatalog_libs; + where &dc_dttmtfmt. le TX_TO; + file executor; + str=cats('%mpe_refreshtables(',libref,')'); + put str; + putlog str; + run; + %inc executor; +%end; %mend dc_refreshcatalog; From e874143a95d0ac2e56c0793e04b979c27f96d74b Mon Sep 17 00:00:00 2001 From: allan Date: Tue, 10 Jun 2025 16:18:56 +0100 Subject: [PATCH 08/14] fix: bumping adapter to re-enable JES API method --- client/package-lock.json | 8 ++++---- client/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index d1b36d3..17146ed 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -21,7 +21,7 @@ "@clr/icons": "^13.0.2", "@clr/ui": "file:libraries/clr-ui-17.9.0.tgz", "@handsontable/angular": "^15.3.0", - "@sasjs/adapter": "^4.12.0", + "@sasjs/adapter": "^4.12.1", "@sasjs/utils": "^3.4.0", "@sheet/crypto": "file:libraries/sheet-crypto.tgz", "@types/d3-graphviz": "^2.6.7", @@ -5912,9 +5912,9 @@ ] }, "node_modules/@sasjs/adapter": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.12.0.tgz", - "integrity": "sha512-1W78CzWyovSNSgjJ36fyckAGrzYqaRyDpjyO+sTchv3JjY0G7ZKw2gaX+NVASDGhKvt4L9PEkJ/Gk7ZG2BSkJA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.12.1.tgz", + "integrity": "sha512-0217oZIkrecOyQygRe6Azgc1C4TIcjB5noi15fU4Rd5GsfDpleKVfQQdzYZ7im/vesWlLIVl/yUT67MMaQe0ew==", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/client/package.json b/client/package.json index 278a3fd..13afe6a 100644 --- a/client/package.json +++ b/client/package.json @@ -49,7 +49,7 @@ "@clr/icons": "^13.0.2", "@clr/ui": "file:libraries/clr-ui-17.9.0.tgz", "@handsontable/angular": "^15.3.0", - "@sasjs/adapter": "^4.12.0", + "@sasjs/adapter": "^4.12.1", "@sasjs/utils": "^3.4.0", "@sheet/crypto": "file:libraries/sheet-crypto.tgz", "@types/d3-graphviz": "^2.6.7", From b4c586a859929e0122cd46449e43d4ca597b8b2b Mon Sep 17 00:00:00 2001 From: allan Date: Tue, 10 Jun 2025 22:40:09 +0100 Subject: [PATCH 09/14] feat: capturing catalog specific information, closes #159 BREAKING CHANGE: Introduction of 4 new tables for capturing information related to catalogs and their objects. Migration script prepared and available in the DB folder (usual place) --- sas/package.json | 4 +- sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl | 4 +- sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl | 4 +- sas/sasjs/db/datactrl/mpe_datastatus_tabs.ddl | 4 +- .../db/migrations/20200428_datacatalog.sas | 6 +- .../db/migrations/20250611_v7.0_release.sas | 68 +++++++++ sas/sasjs/macros/mpe_dsmeta.sas | 23 ++- sas/sasjs/macros/mpe_dsmeta.test.sas | 11 ++ sas/sasjs/macros/mpe_makedatamodel.sas | 4 +- sas/sasjs/macros/mpe_refreshcatalogs.sas | 140 ++++++++++++++++++ sas/sasjs/macros/mpe_refreshcatalogs.test.sas | 38 +++++ sas/sasjs/macros/mpe_refreshtables.sas | 10 +- sas/sasjs/services/editors/getdata.sas | 2 +- sas/sasjs/services/public/viewdata.sas | 2 +- .../sas9/macros_meta/dc_refreshcatalog.sas | 3 + .../macros_server/dc_refreshcatalog.sas | 3 + .../viya/macros_viya/dc_refreshcatalog.sas | 7 +- 17 files changed, 308 insertions(+), 25 deletions(-) create mode 100644 sas/sasjs/db/migrations/20250611_v7.0_release.sas create mode 100644 sas/sasjs/macros/mpe_refreshcatalogs.sas create mode 100644 sas/sasjs/macros/mpe_refreshcatalogs.test.sas diff --git a/sas/package.json b/sas/package.json index 99ad2d1..ce06209 100644 --- a/sas/package.json +++ b/sas/package.json @@ -22,7 +22,7 @@ "serverdata": "sasjs request services/admin/makedata -d deploy/makeDataServer.json -l sasjsresults/makedata_server.log -o sasjsresults/makedata_server.json -t server", "viya": "npm run viyacbd && sasjs test", "viyacbd": "sasjs folder delete /Public/app/viya && sasjs cbd -t viya && npm run viyadata", - "viyadata": "sasjs request services/admin/makedata -d deploy/makeDataViya.json -l sasjsresults/makedata.log -o sasjsresults/output.json", + "viyadata": "sasjs request services/admin/makedata -d deploy/makeDataViya.json -l sasjsresults/makedata.log -o sasjsresults/output.json -t viya", "v4data": "sasjs request services/admin/makedata -d deploy/makeDataV4.json -l sasjsresults/makedatav4.log -o sasjsresults/outputv4.json -t v4", "sasdocs": "sasjs doc && ./sasjs/utils/deploydocs.sh" }, @@ -31,4 +31,4 @@ "@sasjs/cli": "^4.12.8", "@sasjs/core": "^4.59.1" } -} +} \ No newline at end of file diff --git a/sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl b/sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl index 1d223a0..a092b54 100644 --- a/sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl +++ b/sas/sasjs/db/datactrl/mpe_datastatus_cats.ddl @@ -14,7 +14,7 @@ create table &curlib..mpe_datastatus_CATS( libref char(8) label='Library Name', memname char(64) label='Member Name', nobjs num label='Number of objects', - created num format=DATETIME. informat=DATETIME. label='Date Created', - modified num format=DATETIME. informat=DATETIME. label='Date Modified', + created num format=DATETIME. label='Date Created', + modified num format=DATETIME. label='Date Modified', constraint pk_mpe_datastatus_CATS primary key(libref,memname,tx_to)); diff --git a/sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl b/sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl index ec8009b..c73ccfe 100644 --- a/sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl +++ b/sas/sasjs/db/datactrl/mpe_datastatus_objs.ddl @@ -15,8 +15,8 @@ create table &curlib..mpe_datastatus_OBJS( memname char(64) label='Member Name', objname char(32) label='Object Name', objtype char(8) label='Object Type', - created num format=DATETIME. informat=DATETIME. label='Date Created', - modified num format=DATETIME. informat=DATETIME. label='Date Modified', + created num format=DATETIME. label='Date Created', + modified num format=DATETIME. label='Date Modified', level num label='Library Concatenation Level', constraint pk_mpe_datastatus_OBJS primary key(libref,memname,objname,objtype,tx_to)); diff --git a/sas/sasjs/db/datactrl/mpe_datastatus_tabs.ddl b/sas/sasjs/db/datactrl/mpe_datastatus_tabs.ddl index af99604..c4df4d4 100644 --- a/sas/sasjs/db/datactrl/mpe_datastatus_tabs.ddl +++ b/sas/sasjs/db/datactrl/mpe_datastatus_tabs.ddl @@ -14,8 +14,8 @@ create table &curlib..mpe_datastatus_tabs( libref char(8) label='Library Name', dsn char(64) label='Member Name', filesize num format=SIZEKMG. label='Size of file', - crdate num format=DATETIME. informat=DATETIME. label='Date Created', - modate num format=DATETIME. informat=DATETIME. label='Date Modified', + crdate num format=DATETIME. label='Date Created', + modate num format=DATETIME. label='Date Modified', nobs num label='Number of Physical (Actual, inc. deleted) Observations', constraint pk_mpe_datastatus_tabs primary key(libref,dsn,tx_to)); diff --git a/sas/sasjs/db/migrations/20200428_datacatalog.sas b/sas/sasjs/db/migrations/20200428_datacatalog.sas index c0e7a13..907ce69 100644 --- a/sas/sasjs/db/migrations/20200428_datacatalog.sas +++ b/sas/sasjs/db/migrations/20200428_datacatalog.sas @@ -52,7 +52,7 @@ create table dc.mpe_datacatalog_vars( constraint pk primary key(libref,dsn,name,tx_to)); - create table dc.mpe_datastatus_libs( + create table dc.mpe_datastatus_cats( TX_FROM float format=datetime19., TX_TO float format=datetime19., libref char(8) label='Library Name', @@ -67,8 +67,8 @@ create table dc.mpe_datacatalog_vars( libref char(8) label='Library Name', dsn char(64) label='Member Name', filesize num format=SIZEKMG. label='Size of file', - crdate num format=DATETIME. informat=DATETIME. label='Date Created', - modate num format=DATETIME. informat=DATETIME. label='Date Modified', + crdate num format=DATETIME. label='Date Created', + modate num format=DATETIME. label='Date Modified', nobs num label='Number of Physical (Actual, inc. deleted) Observations', constraint pk primary key(libref,dsn,tx_to)); \ No newline at end of file diff --git a/sas/sasjs/db/migrations/20250611_v7.0_release.sas b/sas/sasjs/db/migrations/20250611_v7.0_release.sas new file mode 100644 index 0000000..e5f2dae --- /dev/null +++ b/sas/sasjs/db/migrations/20250611_v7.0_release.sas @@ -0,0 +1,68 @@ +/** + @file + @brief migration script to move from v6.8.2 to v7.0 of data controller + + BREAKING CHANGE - 4 additional tables for capturing catalog information + + Be sure to run this using the correct system account + (eg the regular DC account) + + On SAS 9 you may wish to run proc metalib or refresh in DI Studio afterwards + to see the new tables in the VIEW page + + proc metalib; + omr (library="&DC_LIBNAME"); + folder="&root/data"; + update_rule=(delete); + run; + +**/ + +%let dclib=YOURDCLIB; + +libname &dclib "/YOUR/DATACONTROLLER/LIBRARY/PATH"; + +proc sql; +create table &dclib..mpe_datacatalog_CATS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + constraint pk_mpe_datacatalog_CATS + primary key(libref,memname,tx_to)); + +create table &dclib..mpe_datacatalog_OBJS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + objname char(32) label='Object Name', + objtype char(8) label='Object Type', + objdesc char(256) label='Object Description', + alias char(32) label='Object Alias', + constraint pk_mpe_datacatalog_OBJS + primary key(libref,memname,objname,objtype,tx_to)); + +create table &dclib..mpe_datastatus_CATS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + nobjs num label='Number of objects', + created num format=DATETIME. label='Date Created', + modified num format=DATETIME. label='Date Modified', + constraint pk_mpe_datastatus_CATS + primary key(libref,memname,tx_to)); + +create table &dclib..mpe_datastatus_OBJS( + TX_FROM float format=datetime19., + TX_TO float format=datetime19., + libref char(8) label='Library Name', + memname char(64) label='Member Name', + objname char(32) label='Object Name', + objtype char(8) label='Object Type', + created num format=DATETIME. label='Date Created', + modified num format=DATETIME. label='Date Modified', + level num label='Library Concatenation Level', + constraint pk_mpe_datastatus_OBJS + primary key(libref,memname,objname,objtype,tx_to)); \ No newline at end of file diff --git a/sas/sasjs/macros/mpe_dsmeta.sas b/sas/sasjs/macros/mpe_dsmeta.sas index 58801dc..e372987 100644 --- a/sas/sasjs/macros/mpe_dsmeta.sas +++ b/sas/sasjs/macros/mpe_dsmeta.sas @@ -14,14 +14,31 @@ **/ %macro mpe_dsmeta(libds, outds=dsmeta); - %local ddsd ddld notes lenstmt; + %local ddsd ddld notes lenstmt memname; %let lenstmt=length ods_table $18 name $100 value $1000; %let libds=%upcase(&libds); - %mp_dsmeta(&libds, outds=&outds) + + %if "%scan(&libds,2,-)" ne "FC" %then %do; + %let memname=%scan(&libds,2,.); + %mp_dsmeta(&libds, outds=&outds) + %end; + %else %do; + %let memname=%scan(&libds,2,.-); + data &outds; + &lenstmt; + set sashelp.vcatalg; + ods_table=cats(objtype); + name=cats(objname); + value=catx(' ',objdesc,'(modified:',put(modified,datetime19.),')'); + where libname="%scan(&libds,1,.)" and memname="&memname"; + keep ods_table name value; + run; + proc sort; by ods_table name;run; + %end; data _null_; set &mpelib..mpe_datadictionary; - where &dc_dttmtfmt < tx_to & dd_source=%upcase("&libds") & dd_type='TABLE'; + where &dc_dttmtfmt < tx_to & dd_source="&memname" & dd_type='TABLE'; call symputx('ddsd',dd_shortdesc,'l'); call symputx('ddld',dd_longdesc,'l'); run; diff --git a/sas/sasjs/macros/mpe_dsmeta.test.sas b/sas/sasjs/macros/mpe_dsmeta.test.sas index fd083ca..458d671 100644 --- a/sas/sasjs/macros/mpe_dsmeta.test.sas +++ b/sas/sasjs/macros/mpe_dsmeta.test.sas @@ -34,4 +34,15 @@ run; outds=work.test_results ) +%mpe_dsmeta(FMTONLY.DCFMTS-FC,outds=test2) +data work.test2; + set work.test2; + putlog (_all_)(=); +run; + +%mp_assertdsobs(work.test2, + desc=Test 2 - records returned, + test=EQUALS 5, + outds=work.test_results +) diff --git a/sas/sasjs/macros/mpe_makedatamodel.sas b/sas/sasjs/macros/mpe_makedatamodel.sas index 084e7e5..25878db 100644 --- a/sas/sasjs/macros/mpe_makedatamodel.sas +++ b/sas/sasjs/macros/mpe_makedatamodel.sas @@ -253,8 +253,8 @@ create table &lib..mpe_datastatus_tabs( libref char(8) label='Library Name', dsn char(64) label='Member Name', filesize num format=SIZEKMG. label='Size of file', - crdate num format=DATETIME. informat=DATETIME. label='Date Created', - modate num format=DATETIME. informat=DATETIME. label='Date Modified', + crdate num format=DATETIME. label='Date Created', + modate num format=DATETIME. label='Date Modified', nobs num label='Number of Physical (Actual, inc. deleted) Observations' );quit; proc datasets lib=&lib noprint; diff --git a/sas/sasjs/macros/mpe_refreshcatalogs.sas b/sas/sasjs/macros/mpe_refreshcatalogs.sas new file mode 100644 index 0000000..e41e34b --- /dev/null +++ b/sas/sasjs/macros/mpe_refreshcatalogs.sas @@ -0,0 +1,140 @@ +/** + @file mpe_refreshtables.sas + @brief Refreshes the data catalog + @details Assumes library is already assigned. + Usage: + + %mpe_refreshcatalogs(sashelp) + +

SAS Macros

+ @li bitemporal_dataloader.sas + + @version 9.3 + @author 4GL Apps Ltd +**/ + +%macro mpe_refreshcatalogs(lib,cat=#all); +%let lib=%upcase(&lib); +%let cat=%upcase(&cat); + +%put running &sysmacroname &lib for &cat; +proc sql; +create table work.catdata as + select libname as libref, + memname, + objname, + objtype, + objdesc, + created, + modified, + alias, + level + from dictionary.catalogs + where upcase(libname)="&lib" +%if &cat ne #ALL %then %do; + and upcase(memname)="&cat" +%end; + ; + +%mp_abort(iftrue= (&syscc ne 0) + ,mac=&_program + ,msg=%str(syscc=&syscc afer &lib objects extraction) +) + +/* load mpe_datacatalog_CATS */ +proc sql; +create table datacats as select distinct libref,memname from catdata; + +%bitemporal_dataloader(base_lib=&mpelib + ,base_dsn=mpe_datacatalog_CATS + ,append_dsn=datacats + ,PK=LIBREF MEMNAME + ,etlsource=&sysmacroname + ,loadtype=TXTEMPORAL + ,tech_from=TX_FROM + ,tech_to=TX_TO +%if &cat = #ALL %then %do; + ,close_vars=LIBREF +%end; + ,dclib=&mpelib +) + +/* load mpe_datacatalog_objsS */ +proc sql; +create table dataobjs as + select distinct libref, + memname, + objname, + objtype, + objdesc, + alias + from catdata; +quit; + +%bitemporal_dataloader(base_lib=&mpelib + ,base_dsn=mpe_datacatalog_OBJS + ,append_dsn=dataobjs + ,PK=LIBREF MEMNAME OBJNAME OBJTYPE + ,etlsource=&sysmacroname + ,loadtype=TXTEMPORAL + ,tech_from=TX_FROM + ,tech_to=TX_TO +%if &cat = #ALL %then %do; + ,close_vars=LIBREF MEMNAME +%end; + ,dclib=&mpelib +) + +%put load mpe_datastatus_OBJS; +proc sql; +create table statusobjs as + select distinct libref, + memname, + objname, + objtype, + created, + modified, + level + from catdata; + +%bitemporal_dataloader(base_lib=&mpelib + ,base_dsn=mpe_datastatus_OBJS + ,append_dsn=statusobjs + ,PK=LIBREF MEMNAME OBJNAME OBJTYPE + ,etlsource=&sysmacroname + ,loadtype=TXTEMPORAL + ,tech_from=TX_FROM + ,tech_to=TX_TO +%if &cat = #ALL %then %do; + ,close_vars=LIBREF MEMNAME +%end; + ,dclib=&mpelib +) + +%put load mpe_datastatus_cats; +proc sql; +create table statuscats as + select libref, + memname, + count(*) as nobjs, + min(created) as created, + max(modified) as modified + from catdata + group by 1,2; + +%bitemporal_dataloader(base_lib=&mpelib + ,base_dsn=mpe_datastatus_cats + ,append_dsn=statuscats + ,PK=LIBREF MEMNAME + ,etlsource=&sysmacroname + ,loadtype=TXTEMPORAL + ,tech_from=TX_FROM + ,tech_to=TX_TO +%if &cat = #ALL %then %do; + ,close_vars=LIBREF +%end; + ,dclib=&mpelib +) + + +%mend mpe_refreshcatalogs; diff --git a/sas/sasjs/macros/mpe_refreshcatalogs.test.sas b/sas/sasjs/macros/mpe_refreshcatalogs.test.sas new file mode 100644 index 0000000..940f331 --- /dev/null +++ b/sas/sasjs/macros/mpe_refreshcatalogs.test.sas @@ -0,0 +1,38 @@ +/** + @file + @brief Testing mpe_refreshcatalogs macro + +

SAS Macros

+ @li mpe_refreshcatalogs.sas + @li mp_assert.sas + @li mp_assertscope.sas + @li mp_ds2md.sas + + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd. This code may only be used within Data Controller + and may not be re-distributed or re-sold without the express permission of + 4GL Apps Ltd. + +**/ + +%mp_assertscope(SNAPSHOT) +%mpe_refreshcatalogs(FMTONLY) +%mp_assertscope(COMPARE, + desc=Checking macro variables against previous snapshot +) + +/* make sure that the process picks up the catalog */ +proc sql noprint; +create table work.test1 as + select * + from &mpelib..mpe_datacatalog_cats(where=(&dc_dttmtfmt. lt tx_to)) + where libref="FMTONLY"; +%let test1=0; +select count(*) into: test1 from work.test1; + +%mp_assert( + iftrue=(&test1>0), + desc=Checking fmtonly.dcfmts was picked up +) + +%mp_ds2md(work.test1) \ No newline at end of file diff --git a/sas/sasjs/macros/mpe_refreshtables.sas b/sas/sasjs/macros/mpe_refreshtables.sas index c75d820..171b1aa 100644 --- a/sas/sasjs/macros/mpe_refreshtables.sas +++ b/sas/sasjs/macros/mpe_refreshtables.sas @@ -48,11 +48,6 @@ create table cols as ,msg=%str(syscc=&syscc afer &lib cols extraction) ) -%mp_abort(iftrue= (&syscc ne 0) - ,mac=&_program - ,msg=%str(syscc=&syscc afer &lib indexes extraction) -) - %if &engine=SQLSVR %then %do; proc sql; connect using &lib; @@ -175,6 +170,11 @@ create table cols as %end; +%mp_abort(iftrue= (&syscc ne 0) + ,mac=&_program + ,msg=%str(syscc=&syscc afer &lib indexes extraction) +) + /* load columns */ %bitemporal_dataloader(base_lib=&mpelib ,base_dsn=mpe_datacatalog_vars diff --git a/sas/sasjs/services/editors/getdata.sas b/sas/sasjs/services/editors/getdata.sas index f1be8aa..56ff214 100755 --- a/sas/sasjs/services/editors/getdata.sas +++ b/sas/sasjs/services/editors/getdata.sas @@ -675,7 +675,7 @@ data xl_rules; keep xl_column xl_rule; run; -%mpe_dsmeta(&libds, outds=dsmeta) +%mpe_dsmeta(&orig_libds, outds=dsmeta) %mpe_getversions(&mpelib, %scan(&orig_libds,1,.), diff --git a/sas/sasjs/services/public/viewdata.sas b/sas/sasjs/services/public/viewdata.sas index a59239f..7b72d82 100644 --- a/sas/sasjs/services/public/viewdata.sas +++ b/sas/sasjs/services/public/viewdata.sas @@ -355,7 +355,7 @@ run; %mp_getcols(&libds, outds=cols) -%mpe_dsmeta(&libds, outds=dsmeta) +%mpe_dsmeta(&orig_libds, outds=dsmeta) %mpe_getversions(&mpelib, %scan(&orig_libds,1,.), diff --git a/sas/sasjs/targets/sas9/macros_meta/dc_refreshcatalog.sas b/sas/sasjs/targets/sas9/macros_meta/dc_refreshcatalog.sas index 4fe8293..f508019 100644 --- a/sas/sasjs/targets/sas9/macros_meta/dc_refreshcatalog.sas +++ b/sas/sasjs/targets/sas9/macros_meta/dc_refreshcatalog.sas @@ -9,6 +9,7 @@

SAS Macros

@li mpe_refreshlibs.sas @li dc_assignlib.sas + @li mpe_refreshcatalogs.sas @li mpe_refreshtables.sas @li mm_getrepos.sas @@ -44,6 +45,7 @@ run; %dc_assignlib(WRITE,&libref) /* write just in order to assign direct lib */ %mpe_refreshlibs(lib=&libref) %mpe_refreshtables(&libref) + %mpe_refreshcatalogs(&libref) %end; %else %do xx=1 %to &repocnt; options metarepository=&&repo&xx; @@ -73,6 +75,7 @@ run; %do i=1 %to &libcnt; %dc_assignlib(WRITE,&&lib&i) %mpe_refreshtables(&&lib&i) + %mpe_refreshcatalogs(&&lib&i) %end; %end; diff --git a/sas/sasjs/targets/server/macros_server/dc_refreshcatalog.sas b/sas/sasjs/targets/server/macros_server/dc_refreshcatalog.sas index 80e70e0..0305709 100644 --- a/sas/sasjs/targets/server/macros_server/dc_refreshcatalog.sas +++ b/sas/sasjs/targets/server/macros_server/dc_refreshcatalog.sas @@ -9,6 +9,7 @@

SAS Macros

@li mpe_refreshlibs.sas @li dc_assignlib.sas + @li mpe_refreshcatalogs.sas @li mpe_refreshtables.sas @@ -34,6 +35,8 @@ data libraries; str=cats('%mpe_refreshtables(',libref,')'); put str; putlog str; + str=cats('%mpe_refreshcatalogs(',libref,')'); + put str; run; %inc executor/source2; diff --git a/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas b/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas index f984e43..f4f2bc2 100644 --- a/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas +++ b/sas/sasjs/targets/viya/macros_viya/dc_refreshcatalog.sas @@ -10,6 +10,7 @@ @li mpe_refreshlibs.sas @li dc_assignlib.sas @li mpe_refreshtables.sas + @li mpe_refreshcatalogs.sas @version 3.4 @@ -21,15 +22,15 @@ %macro dc_refreshcatalog(libref); -%mpe_refreshlibs() - %if #&libref# ne ## %then %do; %put &sysmacroname: assigning specific libref, &libref; %dc_assignlib(WRITE,&libref) /* write just in order to assign direct lib */ %mpe_refreshlibs(lib=&libref) %mpe_refreshtables(&libref) + %mpe_refreshcatalogs(&libref) %end; %else %do; + %mpe_refreshlibs() filename executor catalog 'work.code.code.source'; data libraries; set &mpelib..mpe_datacatalog_libs; @@ -37,6 +38,8 @@ file executor; str=cats('%mpe_refreshtables(',libref,')'); put str; + str=cats('%mpe_refreshcatalogs(',libref,')'); + put str; putlog str; run; %inc executor; From efb5ffa90697296278d789252ff01614a319691f Mon Sep 17 00:00:00 2001 From: allan Date: Tue, 10 Jun 2025 22:45:39 +0100 Subject: [PATCH 10/14] chore: reverting accidental change --- sas/sasjs/db/migrations/20200428_datacatalog.sas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sas/sasjs/db/migrations/20200428_datacatalog.sas b/sas/sasjs/db/migrations/20200428_datacatalog.sas index 907ce69..d503a86 100644 --- a/sas/sasjs/db/migrations/20200428_datacatalog.sas +++ b/sas/sasjs/db/migrations/20200428_datacatalog.sas @@ -52,7 +52,7 @@ create table dc.mpe_datacatalog_vars( constraint pk primary key(libref,dsn,name,tx_to)); - create table dc.mpe_datastatus_cats( + create table dc.mpe_datastatus_libs( TX_FROM float format=datetime19., TX_TO float format=datetime19., libref char(8) label='Library Name', From e44a25dcc39ba4b9714257c60da84c2dfa613a85 Mon Sep 17 00:00:00 2001 From: allan Date: Wed, 11 Jun 2025 10:06:52 +0100 Subject: [PATCH 11/14] fix: showing catalog_cnt in libinfo Closes #160 --- sas/sasjs/db/datactrl/mpe_datastatus_libs.ddl | 1 + .../db/migrations/20200428_datacatalog.sas | 2 +- .../db/migrations/20250611_v7.0_release.sas | 5 +- sas/sasjs/macros/mpe_makedatamodel.sas | 3 +- sas/sasjs/macros/mpe_refreshtables.sas | 13 +- sas/sasjs/macros/mpe_refreshtables.test.sas | 3 +- sas/sasjs/services/public/refreshlibinfo.sas | 171 +++++++++--------- sas/sasjs/services/public/viewtables.sas | 3 +- 8 files changed, 110 insertions(+), 91 deletions(-) diff --git a/sas/sasjs/db/datactrl/mpe_datastatus_libs.ddl b/sas/sasjs/db/datactrl/mpe_datastatus_libs.ddl index b4516dc..28e5ce6 100644 --- a/sas/sasjs/db/datactrl/mpe_datastatus_libs.ddl +++ b/sas/sasjs/db/datactrl/mpe_datastatus_libs.ddl @@ -14,5 +14,6 @@ create table &curlib..mpe_datastatus_libs( libref char(8) label='Library Name', libsize num format=SIZEKMG. label='Size of file', table_cnt num label='Number of Tables', + catalog_cnt num label='Number of Catalogs', constraint pk_mpe_datastatus_libs primary key(libref,tx_to)); diff --git a/sas/sasjs/db/migrations/20200428_datacatalog.sas b/sas/sasjs/db/migrations/20200428_datacatalog.sas index d503a86..448bf67 100644 --- a/sas/sasjs/db/migrations/20200428_datacatalog.sas +++ b/sas/sasjs/db/migrations/20200428_datacatalog.sas @@ -29,7 +29,7 @@ create table dc.mpe_datacatalog_TABS( nvar num label='Number of Variables', compress char(8) label='Compression Routine', pk_fields char(512) - label='Primary Key Fields (identified by being in a constraint that is both Unique and Not Null)', + label='Primary Key Fields (in a constraint that is both Unique and Not Null)', constraint pk primary key(libref,dsn,tx_to)); diff --git a/sas/sasjs/db/migrations/20250611_v7.0_release.sas b/sas/sasjs/db/migrations/20250611_v7.0_release.sas index e5f2dae..d666d89 100644 --- a/sas/sasjs/db/migrations/20250611_v7.0_release.sas +++ b/sas/sasjs/db/migrations/20250611_v7.0_release.sas @@ -2,7 +2,7 @@ @file @brief migration script to move from v6.8.2 to v7.0 of data controller - BREAKING CHANGE - 4 additional tables for capturing catalog information + BREAKING CHANGE - 1 new column and 4 additional tables for capturing catalogs Be sure to run this using the correct system account (eg the regular DC account) @@ -23,6 +23,9 @@ libname &dclib "/YOUR/DATACONTROLLER/LIBRARY/PATH"; proc sql; +create table work.BACKUP as select * from &dclib..mpe_datastatus_libs; +alter table &dclib..mpe_datastatus_libs add catalog_cnt num; + create table &dclib..mpe_datacatalog_CATS( TX_FROM float format=datetime19., TX_TO float format=datetime19., diff --git a/sas/sasjs/macros/mpe_makedatamodel.sas b/sas/sasjs/macros/mpe_makedatamodel.sas index 25878db..f9862f1 100644 --- a/sas/sasjs/macros/mpe_makedatamodel.sas +++ b/sas/sasjs/macros/mpe_makedatamodel.sas @@ -220,7 +220,8 @@ create table &lib..mpe_datastatus_libs( TX_TO num ¬null format=datetime19.3, libref char(8) label='Library Name', libsize num format=SIZEKMG. label='Size of library', - table_cnt num label='Number of Tables' + table_cnt num label='Number of Tables', + catalog_cnt num label='Number of Catalogs' );quit; proc datasets lib=&lib noprint; modify mpe_datastatus_libs; diff --git a/sas/sasjs/macros/mpe_refreshtables.sas b/sas/sasjs/macros/mpe_refreshtables.sas index 171b1aa..0baab24 100644 --- a/sas/sasjs/macros/mpe_refreshtables.sas +++ b/sas/sasjs/macros/mpe_refreshtables.sas @@ -314,12 +314,23 @@ proc sql; %if &ds = #ALL %then %do; proc sql; - create table statuslibs as select + create table work.sumcat as + select libname as libref, + count(distinct memname) as catalog_cnt + from dictionary.catalogs + where upcase(libname)="&lib" + group by 1; + create table work.sumdsn as select libref ,sum(filesize) as libsize ,count(*) as table_cnt from statustabs group by 1; + create table work.statuslibs as + select a.*, b.catalog_cnt + from work.sumdsn a + full join work.sumcat b + on a.libref=b.libref; %bitemporal_dataloader(base_lib=&mpelib ,base_dsn=mpe_datastatus_libs diff --git a/sas/sasjs/macros/mpe_refreshtables.test.sas b/sas/sasjs/macros/mpe_refreshtables.test.sas index ba28673..d3ce789 100644 --- a/sas/sasjs/macros/mpe_refreshtables.test.sas +++ b/sas/sasjs/macros/mpe_refreshtables.test.sas @@ -32,7 +32,8 @@ create table work.libinfo as a.schemas, a.libid, b.libsize, - b.table_cnt + b.table_cnt, + b.catalog_cnt from &mpelib..mpe_datacatalog_libs(where=(&dc_dttmtfmt. lt tx_to)) a left join &mpelib..mpe_datastatus_libs(where=(&dc_dttmtfmt. lt tx_to)) b on a.libref=b.libref diff --git a/sas/sasjs/services/public/refreshlibinfo.sas b/sas/sasjs/services/public/refreshlibinfo.sas index b971b29..033a243 100644 --- a/sas/sasjs/services/public/refreshlibinfo.sas +++ b/sas/sasjs/services/public/refreshlibinfo.sas @@ -1,85 +1,86 @@ -/** - @file refreshlibinfo.sas - @brief Refresh the Data Catalog for a particular library - @details When showing library info in the VIEW menu, the data is taken from - the Data Catalog tables. These may be empty or outdated, and so this service - allows end users to run a refresh of the data. - -

Service Inputs

-
lib2refresh
- Should contain the libref to be refreshed. - |libref:$8.| - |---| - |SOMELIB| - -

Service Outputs

- -
libinfo
- - |engine $|libname $|paths $|perms $|owners $|schemas $ |libid $|libsize $|table_cnt | - |---|---|---|---|---|---|---|---|---| - |V9|SOMELIB|"some/path"|rwxrwxr-x|sassrv|` `|` `|636MB|33| - -

SAS Macros

- @li dc_assignlib.sas - @li dc_refreshcatalog.sas - @li mp_abort.sas - - @version 9.3 - @author 4GL Apps Ltd - @copyright 4GL Apps Ltd. This code may only be used within Data Controller - and may not be re-distributed or re-sold without the express permission of - 4GL Apps Ltd. -**/ - - -%mpeinit() - -%webout(FETCH) - -%mp_abort(iftrue= (&syscc ne 0) - ,msg=%str(syscc=&syscc Problem on startup) -) - -%let libref=; -data _null_; - set work.lib2refresh; - call symputx('libref',libref); -run; - -%mp_abort(iftrue= (&syscc ne 0) - ,msg=%str(syscc=&syscc Problem with inputs - was lib2refresh object sent?) -) - -%dc_assignlib(WRITE,&libref) - -%mp_abort(iftrue= (&syscc ne 0) - ,msg=%str(syscc=&syscc after lib assignment) -) - -%dc_refreshcatalog(&libref) - -%mp_abort(iftrue= (&syscc ne 0) - ,msg=%str(syscc=&syscc Problem when running the catalog refresh) -) - -/* get libinfo */ -proc sql; -create table work.libinfo as - select a.engine, - a.libname, - a.paths, - a.perms, - a.owners, - a.schemas, - a.libid, - b.libsize, - b.table_cnt - from &mpelib..mpe_datacatalog_libs(where=(&dc_dttmtfmt. lt tx_to)) a - inner join &mpelib..mpe_datastatus_libs(where=(&dc_dttmtfmt. lt tx_to)) b - on a.libref=b.libref - where a.libref="&libref"; - -%webout(OPEN) -%webout(OBJ,libinfo) -%webout(CLOSE) +/** + @file refreshlibinfo.sas + @brief Refresh the Data Catalog for a particular library + @details When showing library info in the VIEW menu, the data is taken from + the Data Catalog tables. These may be empty or outdated, and so this service + allows end users to run a refresh of the data. + +

Service Inputs

+
lib2refresh
+ Should contain the libref to be refreshed. + |libref:$8.| + |---| + |SOMELIB| + +

Service Outputs

+ +
libinfo
+ + |engine $|libname $|paths $|perms $|owners $|schemas $ |libid $|libsize $|table_cnt | + |---|---|---|---|---|---|---|---|---| + |V9|SOMELIB|"some/path"|rwxrwxr-x|sassrv|` `|` `|636MB|33| + +

SAS Macros

+ @li dc_assignlib.sas + @li dc_refreshcatalog.sas + @li mp_abort.sas + + @version 9.3 + @author 4GL Apps Ltd + @copyright 4GL Apps Ltd. This code may only be used within Data Controller + and may not be re-distributed or re-sold without the express permission of + 4GL Apps Ltd. +**/ + + +%mpeinit() + +%webout(FETCH) + +%mp_abort(iftrue= (&syscc ne 0) + ,msg=%str(syscc=&syscc Problem on startup) +) + +%let libref=; +data _null_; + set work.lib2refresh; + call symputx('libref',libref); +run; + +%mp_abort(iftrue= (&syscc ne 0) + ,msg=%str(syscc=&syscc Problem with inputs - was lib2refresh object sent?) +) + +%dc_assignlib(WRITE,&libref) + +%mp_abort(iftrue= (&syscc ne 0) + ,msg=%str(syscc=&syscc after lib assignment) +) + +%dc_refreshcatalog(&libref) + +%mp_abort(iftrue= (&syscc ne 0) + ,msg=%str(syscc=&syscc Problem when running the catalog refresh) +) + +/* get libinfo */ +proc sql; +create table work.libinfo as + select a.engine, + a.libname, + a.paths, + a.perms, + a.owners, + a.schemas, + a.libid, + b.libsize, + b.table_cnt, + b.catalog_cnt + from &mpelib..mpe_datacatalog_libs(where=(&dc_dttmtfmt. lt tx_to)) a + inner join &mpelib..mpe_datastatus_libs(where=(&dc_dttmtfmt. lt tx_to)) b + on a.libref=b.libref + where a.libref="&libref"; + +%webout(OPEN) +%webout(OBJ,libinfo) +%webout(CLOSE) diff --git a/sas/sasjs/services/public/viewtables.sas b/sas/sasjs/services/public/viewtables.sas index d95d0ef..6a88221 100644 --- a/sas/sasjs/services/public/viewtables.sas +++ b/sas/sasjs/services/public/viewtables.sas @@ -167,7 +167,8 @@ create table work.libinfo as a.schemas, a.libid, coalesce(b.libsize,0) as libsize, - coalesce(b.table_cnt,0) as table_cnt + coalesce(b.table_cnt,0) as table_cnt, + coalesce(b.catalog_cnt,0) as catalog_cnt from &mpelib..mpe_datacatalog_libs(where=(&dc_dttmtfmt. lt tx_to)) a left join &mpelib..mpe_datastatus_libs(where=(&dc_dttmtfmt. lt tx_to)) b on a.libref=b.libref From 2aa19d1dca747f41274a032cde78d8ba73d66224 Mon Sep 17 00:00:00 2001 From: Mihajlo Medjedovic Date: Wed, 11 Jun 2025 12:57:10 +0200 Subject: [PATCH 12/14] feat: viewer added catalog_cnt --- client/src/app/models/sas/common/Libinfo.ts | 1 + client/src/app/viewer/viewer.component.html | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/client/src/app/models/sas/common/Libinfo.ts b/client/src/app/models/sas/common/Libinfo.ts index 425a143..07fb2fa 100644 --- a/client/src/app/models/sas/common/Libinfo.ts +++ b/client/src/app/models/sas/common/Libinfo.ts @@ -8,4 +8,5 @@ export interface Libinfo { LIBID: string LIBSIZE: number TABLE_CNT: number + CATALOG_CNT: number } diff --git a/client/src/app/viewer/viewer.component.html b/client/src/app/viewer/viewer.component.html index e4a7cce..e4934b0 100644 --- a/client/src/app/viewer/viewer.component.html +++ b/client/src/app/viewer/viewer.component.html @@ -598,6 +598,12 @@ {{ libinfo[0] ? libinfo[0].TABLE_CNT : '' }} + + CATALOG_CNT: + + {{ libinfo[0] ? libinfo[0].CATALOG_CNT : '' }} + + From 69f687a85f1cc562346b6167813d617cb9bd3404 Mon Sep 17 00:00:00 2001 From: Mihajlo Medjedovic Date: Wed, 11 Jun 2025 13:11:30 +0200 Subject: [PATCH 13/14] fix: commit git hooks checking lint --- .git-hooks/pre-commit | 15 ++++++++------- client/src/app/viewer/viewer.component.html | 2 +- package.json | 4 +++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.git-hooks/pre-commit b/.git-hooks/pre-commit index f617074..0232fdd 100755 --- a/.git-hooks/pre-commit +++ b/.git-hooks/pre-commit @@ -1,11 +1,12 @@ #!/bin/sh -# Avoid commits to the master branch -BRANCH=`git rev-parse --abbrev-ref HEAD` -REGEX="^(master|development)$" +# Using `--silent` helps for showing any errs in the first line of the response +# The first line is picked up by the VS Code GIT UI popup when rc is not 0 -if [[ "$BRANCH" =~ $REGEX ]]; then - echo "You are on branch $BRANCH. Are you sure you want to commit to this branch?" - echo "If so, commit with -n to bypass the pre-commit hook." - exit 1 +if npm run --silent lint:silent ; then + exit 0 +else + npm run --silent lint:fix + echo "❌ Prettier check failed! We ran lint:fix for you. Please add & commit again." + exit 1 fi diff --git a/client/src/app/viewer/viewer.component.html b/client/src/app/viewer/viewer.component.html index e4934b0..49cddb0 100644 --- a/client/src/app/viewer/viewer.component.html +++ b/client/src/app/viewer/viewer.component.html @@ -598,7 +598,7 @@ {{ libinfo[0] ? libinfo[0].TABLE_CNT : '' }} - + CATALOG_CNT: {{ libinfo[0] ? libinfo[0].CATALOG_CNT : '' }} diff --git a/package.json b/package.json index 14ee23d..c9710b4 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "lint": "npm run lint:fix", "lint:fix": "npx prettier --write \"client/{src,test}/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\" \"client/cypress/integration/*.tests.ts\"", "lint:check": "npx prettier --check \"client/{src,test}/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\" \"client/cypress/integration/*.tests.ts\"", - "jo": "echo" + "lint:silent": "npx prettier --loglevel silent --check \"client/{src,test}/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\" \"client/cypress/integration/*.tests.ts\"", + "jo": "echo", + "prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks && git config core.autocrlf false || true" }, "repository": { "type": "git", From d1998422d204157fcfc7d4f2c203b69aa730ab32 Mon Sep 17 00:00:00 2001 From: allan Date: Wed, 11 Jun 2025 14:15:50 +0100 Subject: [PATCH 14/14] chore: fix for mpe_datastatus_libs --- sas/sasjs/macros/mpe_refreshtables.sas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sas/sasjs/macros/mpe_refreshtables.sas b/sas/sasjs/macros/mpe_refreshtables.sas index 0baab24..d3388a5 100644 --- a/sas/sasjs/macros/mpe_refreshtables.sas +++ b/sas/sasjs/macros/mpe_refreshtables.sas @@ -327,7 +327,10 @@ proc sql; from statustabs group by 1; create table work.statuslibs as - select a.*, b.catalog_cnt + select coalesce(a.libref,b.libref) as libref, + a.libsize, + a.table_cnt, + b.catalog_cnt from work.sumdsn a full join work.sumcat b on a.libref=b.libref;