1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-09 10:20:06 +00:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Allan Bowe
76a39cad20 Merge pull request #138 from sasjs/webout_mac
fix: adding missing param to mx_createwebservice macros
2021-12-30 16:29:50 +02:00
munja
ebd567af48 fix: adding missing param to mx_createwebservice macros 2021-12-30 09:53:08 +00:00
Allan Bowe
a9c418e3f2 Merge pull request #137 from sasjs/specials
feat: updating mp_jsonout() to support special missing numeric values.
2021-12-30 11:43:00 +02:00
munja
e143acd67d chore: automated commit 2021-12-30 00:30:14 +00:00
munja
84eb2f1845 chore: automated commit 2021-12-30 00:29:48 +00:00
munja
b075e5d5d5 feat: updating mp_jsonout() to support special missing numeric values. Closes #136 2021-12-30 00:21:02 +00:00
Allan Bowe
a08f6aeea2 Merge pull request #135 from sasjs/abortfix
fix: removing 'Log Extract' from abort MSG in mp_abort when not capturing the log
2021-12-29 14:54:01 +02:00
munja
469bd574ac fix: removing 'Log Extract' from abort MSG in mp_abort when not capturing the log 2021-12-29 12:35:25 +00:00
Allan Bowe
c41918c0a8 Merge pull request #134 from sasjs/fmtfix
fix: preventing error when mp_applyformats has no formats to apply
2021-12-29 14:19:59 +02:00
munja
0361ca574d fix: preventing error when mp_applyformats has no formats to apply 2021-12-29 12:19:34 +00:00
Allan Bowe
c75c169b80 Merge pull request #133 from sasjs/fmtname
fix: adding fmtname to mp_getcols() macro
2021-12-28 15:39:07 +02:00
munja
eac47bd5db fix: adding fmtname to mp_getcols() macro 2021-12-28 13:25:53 +00:00
munja
d302ef266d chore: doc page formatting & content 2021-12-27 11:54:46 +00:00
17 changed files with 407 additions and 210 deletions

View File

@@ -188,6 +188,13 @@ When contributing to this library, it is therefore important to ensure that all
- All macros should be compatible with SAS versions from support level B and above (so currently 9.2 and later). If an earlier version is not supported, then the macro should say as such in the header documentation, and exit gracefully (eg `%if %sysevalf(&sysver<9.3) %then %return`). - All macros should be compatible with SAS versions from support level B and above (so currently 9.2 and later). If an earlier version is not supported, then the macro should say as such in the header documentation, and exit gracefully (eg `%if %sysevalf(&sysver<9.3) %then %return`).
## Breaking Changes
We are currently on major release v3. The following changes are planned when the next major (breaking) release becomes necessary:
* Remove `dbg` parameter from mp_jsonout.sas (implement mdebug instead)
* Remove `END_DTTM` and `START_DTTM` from mx_webout JSON
## Star Gazing ## Star Gazing
If you find this library useful, please leave a [star](https://github.com/sasjs/core/stargazers) and help us grow our star graph! If you find this library useful, please leave a [star](https://github.com/sasjs/core/stargazers) and help us grow our star graph!

206
all.sas
View File

@@ -2135,8 +2135,8 @@ Usage:
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG; %if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
%else %let logloc=%qsysfunc(getoption(LOG)); %else %let logloc=%qsysfunc(getoption(LOG));
proc printto log=log;run; proc printto log=log;run;
%if %length(&logloc)>0 %then %do;
%let logline=0; %let logline=0;
%if %length(&logloc)>0 %then %do;
data _null_; data _null_;
infile &logloc lrecl=5000; infile &logloc lrecl=5000;
input; putlog _infile_; input; putlog _infile_;
@@ -2185,7 +2185,10 @@ Usage:
file _webout mod lrecl=32000 encoding='utf-8'; file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 ; length msg $32767 ;
sasdatetime=datetime(); sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg')); msg=symget('msg');
%if &logline>0 %then %do;
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
%end;
/* escape the quotes */ /* escape the quotes */
msg=tranwrd(msg,'"','\"'); msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */ /* ditch the CRLFs as chrome complains */
@@ -2478,16 +2481,16 @@ run;
proc sql noprint; proc sql noprint;
select distinct lib into: liblist separated by ' ' from &inds; select distinct lib into: liblist separated by ' ' from &inds;
%put &=liblist; %put &=liblist;
%do i=1 %to %sysfunc(countw(&liblist)); %if %length(&liblist)>0 %then %do i=1 %to %sysfunc(countw(&liblist));
%let lib=%scan(&liblist,1); %let lib=%scan(&liblist,1);
%let engine=%mf_getengine(&lib); %let engine=%mf_getengine(&lib);
%if &engine ne V9 and &engine ne BASE %then %do; %if &engine ne V9 and &engine ne BASE %then %do;
%let msg=&lib has &engine engine - formats cannot be applied; %let msg=&lib has &engine engine - formats cannot be applied;
proc sql;
insert into &outds set lib="&lib",ds="_all_",var="_all", msg="&msg" ; insert into &outds set lib="&lib",ds="_all_",var="_all", msg="&msg" ;
%if &errds=0 %then %put %str(ERR)OR: &msg; %if &errds=0 %then %put %str(ERR)OR: &msg;
%end; %end;
%end; %end;
quit;
%if %mf_nobs(&outds)>0 %then %return; %if %mf_nobs(&outds)>0 %then %return;
@@ -5539,11 +5542,11 @@ filename &fref1 clear;
@param ds The dataset from which to obtain column metadata @param ds The dataset from which to obtain column metadata
@param outds= (work.cols) The output dataset to create. Sample data: @param outds= (work.cols) The output dataset to create. Sample data:
|NAME $|LENGTH 8|VARNUM 8|LABEL $|FORMAT $49|TYPE $1 |DDTYPE $| |NAME:$32.|LENGTH:best.|VARNUM:best.|LABEL:$256.|FMTNAME:$32.|FORMAT:$49.|TYPE:$1.|DDTYPE:$9.|
|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|---|
|AIR|8|2|international airline travel (thousands)|8.|N|NUMERIC| |`AIR `|`8 `|`2 `|`international airline travel (thousands) `|` `|`8. `|`N `|`NUMERIC `|
|DATE|8|1|DATE|MONYY.|N|DATE| |`DATE `|`8 `|`1 `|`DATE `|`MONYY `|`MONYY. `|`N `|`DATE `|
|REGION|3|3|REGION|$3.|C|CHARACTER| |`REGION `|`3 `|`3 `|`REGION `|` `|`$3. `|`C `|`CHARACTER `|
<h4> Related Macros </h4> <h4> Related Macros </h4>
@li mf_getvarlist.sas @li mf_getvarlist.sas
@@ -5555,26 +5558,27 @@ filename &fref1 clear;
**/ **/
%macro mp_getcols(ds, outds=work.cols); %macro mp_getcols(ds, outds=work.cols);
%local dropds;
proc contents noprint data=&ds proc contents noprint data=&ds
out=_data_ (keep=name type length label varnum format:); out=_data_ (keep=name type length label varnum format:);
run; run;
data &outds(keep=name type length varnum format label ddtype); %let dropds=&syslast;
set &syslast(rename=(format=format2 type=type2)); data &outds(keep=name type length varnum format label ddtype fmtname);
set &dropds(rename=(format=fmtname type=type2));
name=upcase(name); name=upcase(name);
if type2=2 then do; if type2=2 then do;
length format $49.; length format $49.;
if format2='' then format=cats('$',length,'.'); if fmtname='' then format=cats('$',length,'.');
else if formatl=0 then format=cats(format2,'.'); else if formatl=0 then format=cats(fmtname,'.');
else format=cats(format2,formatl,'.'); else format=cats(fmtname,formatl,'.');
type='C'; type='C';
ddtype='CHARACTER'; ddtype='CHARACTER';
end; end;
else do; else do;
if format2='' then format=cats(length,'.'); if fmtname='' then format=cats(length,'.');
else if formatl=0 then format=cats(format2,'.'); else if formatl=0 then format=cats(fmtname,'.');
else if formatd=0 then format=cats(format2,formatl,'.'); else if formatd=0 then format=cats(fmtname,formatl,'.');
else format=cats(format2,formatl,'.',formatd); else format=cats(fmtname,formatl,'.',formatd);
type='N'; type='N';
if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME'; if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME';
else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY' else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
@@ -5586,7 +5590,8 @@ data &outds(keep=name type length varnum format label ddtype);
end; end;
if label='' then label=name; if label='' then label=name;
run; run;
proc sql;
drop table &dropds;
%mend mp_getcols;/** %mend mp_getcols;/**
@file mp_getconstraints.sas @file mp_getconstraints.sas
@brief Get constraint details at column level @brief Get constraint details at column level
@@ -7535,22 +7540,20 @@ filename &tempref clear;
[sasjs adapter](https://github.com/sasjs/adapter). [sasjs adapter](https://github.com/sasjs/adapter).
For more information see https://sasjs.io For more information see https://sasjs.io
@param action Valid values: @param [in] action Valid values:
@li OPEN - opens the JSON @li OPEN - opens the JSON
@li OBJ - sends a table with each row as an object @li OBJ - sends a table with each row as an object
@li ARR - sends a table with each row in an array @li ARR - sends a table with each row in an array
@li CLOSE - closes the JSON @li CLOSE - closes the JSON
@param [in] ds The dataset to send. Must be a work table.
@param ds the dataset to send. Must be a work table. @param [out] jref= (_webout) The fileref to which to send the JSON
@param jref= the fileref to which to send the JSON @param [out] dslabel= The name to give the table in the exported JSON
@param dslabel= the name to give the table in the exported JSON @param [in] fmt= (Y) Whether to keep (Y) or strip (N) formats from the table
@param fmt= Whether to keep or strip formats from the table @param [in] engine= (DATASTEP) Which engine to use to send the JSON. Options:
@param engine= Which engine to use to send the JSON, valid options are:
@li PROCJSON (default) @li PROCJSON (default)
@li DATASTEP (more reliable when data has non standard characters) @li DATASTEP (more reliable when data has non standard characters)
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
@param dbg= DEPRECATED - was used to conditionally add PRETTY to (eg `null`) or as STRING values (eg `".a"` or `".b"`)
proc json but this can cause line truncation in large files.
<h4> Related Macros <h4> <h4> Related Macros <h4>
@li mp_ds2fmtds.sas @li mp_ds2fmtds.sas
@@ -7561,9 +7564,11 @@ filename &tempref clear;
**/ **/
%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP,dbg=0 %macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP
,dbg=0 /* DEPRECATED */
,missing=NULL
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%put output location=&jref; %put &sysmacroname: output location=&jref;
%if &action=OPEN %then %do; %if &action=OPEN %then %do;
options nobomfile; options nobomfile;
data _null_;file &jref encoding='utf-8' ; data _null_;file &jref encoding='utf-8' ;
@@ -7576,10 +7581,16 @@ filename &tempref clear;
put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":";
%if &engine=PROCJSON %then %do; %if &engine=PROCJSON %then %do;
%if &missing=STRING %then %do;
%put &sysmacroname: Special Missings are not supported in proc json.;
%put &sysmacroname: Switching to DATASTEP engine;
%goto datastep;
%end;
data;run;%let tempds=&syslast; data;run;%let tempds=&syslast;
proc sql;drop table &tempds; proc sql;drop table &tempds;
data &tempds /view=&tempds;set &ds; data &tempds /view=&tempds;set &ds;
%if &fmt=N %then format _numeric_ best32.;; %if &fmt=N %then format _numeric_ best32.;;
/* PRETTY is necessary to avoid line truncation in large files */
proc json out=&jref pretty proc json out=&jref pretty
%if &action=ARR %then nokeys ; %if &action=ARR %then nokeys ;
;export &tempds / nosastags fmtnumeric; ;export &tempds / nosastags fmtnumeric;
@@ -7587,6 +7598,7 @@ filename &tempref clear;
proc sql;drop view &tempds; proc sql;drop view &tempds;
%end; %end;
%else %if &engine=DATASTEP %then %do; %else %if &engine=DATASTEP %then %do;
%datastep:
%local cols i tempds; %local cols i tempds;
%let cols=0; %let cols=0;
%if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do;
@@ -7667,7 +7679,15 @@ filename &tempref clear;
run; run;
proc format; /* credit yabwon for special null removal */ proc format; /* credit yabwon for special null removal */
value bart ._ - .z = null value bart
%if &missing=NULL %then %do;
._ - .z = null
%end;
%else %do;
._ = [quote()]
. = null
.a - .z = [quote()]
%end;
other = [best.]; other = [best.];
data;run; %let tempds=&syslast; /* temp table for spesh char management */ data;run; %let tempds=&syslast; /* temp table for spesh char management */
@@ -12651,9 +12671,11 @@ data _null_;
put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */"; put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */";
/* WEBOUT BEGIN */ /* WEBOUT BEGIN */
put ' '; put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP,dbg=0 '; put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP ';
put ' ,dbg=0 /* DEPRECATED */ ';
put ' ,missing=NULL ';
put ')/*/STORE SOURCE*/; '; put ')/*/STORE SOURCE*/; ';
put '%put output location=&jref; '; put '%put &sysmacroname: output location=&jref; ';
put '%if &action=OPEN %then %do; '; put '%if &action=OPEN %then %do; ';
put ' options nobomfile; '; put ' options nobomfile; ';
put ' data _null_;file &jref encoding=''utf-8'' ; '; put ' data _null_;file &jref encoding=''utf-8'' ; ';
@@ -12666,10 +12688,16 @@ data _null_;
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' '; put ' ';
put ' %if &engine=PROCJSON %then %do; '; put ' %if &engine=PROCJSON %then %do; ';
put ' %if &missing=STRING %then %do; ';
put ' %put &sysmacroname: Special Missings are not supported in proc json.; ';
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; ';
put ' %end; ';
put ' data;run;%let tempds=&syslast; '; put ' data;run;%let tempds=&syslast; ';
put ' proc sql;drop table &tempds; '; put ' proc sql;drop table &tempds; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds /view=&tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
@@ -12677,6 +12705,7 @@ data _null_;
put ' proc sql;drop view &tempds; '; put ' proc sql;drop view &tempds; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: ';
put ' %local cols i tempds; '; put ' %local cols i tempds; ';
put ' %let cols=0; '; put ' %let cols=0; ';
put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; '; put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; ';
@@ -12757,7 +12786,15 @@ data _null_;
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' proc format; /* credit yabwon for special null removal */ '; put ' proc format; /* credit yabwon for special null removal */ ';
put ' value bart ._ - .z = null '; put ' value bart ';
put ' %if &missing=NULL %then %do; ';
put ' ._ - .z = null ';
put ' %end; ';
put ' %else %do; ';
put ' ._ = [quote()] ';
put ' . = null ';
put ' .a - .z = [quote()] ';
put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ '; put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ ';
@@ -12825,7 +12862,7 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%mend mp_jsonout; '; put '%mend mp_jsonout; ';
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); '; put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug '; put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; '; put ' sasjs_tables; ';
put '%local i tempds jsonengine; '; put '%local i tempds jsonengine; ';
@@ -12890,7 +12927,7 @@ data _null_;
put ' '; put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; '; put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref '; put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=&jsonengine,dbg=%str(&_debug) '; put ' ,engine=&jsonengine,missing=&missing ';
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
@@ -12980,8 +13017,8 @@ data _null_;
put ' '; put ' ';
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
/* WEBOUT END */ /* WEBOUT END */
put '%macro webout(action,ds,dslabel=,fmt=);'; put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL);';
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt)'; put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing)';
put '%mend;'; put '%mend;';
run; run;
@@ -16310,17 +16347,19 @@ run;
%mm_webout(CLOSE) %mm_webout(CLOSE)
@param action Either FETCH, OPEN, ARR, OBJ or CLOSE @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
@param ds The dataset to send back to the frontend @param [in] ds The dataset to send back to the frontend
@param dslabel= value to use instead of the real name for sending to JSON @param [out] dslabel= Value to use instead of table name for sending to JSON
@param fmt=(Y) Set to N to send back unformatted values @param [in] fmt=(Y) Set to N to send back unformatted values
@param fref=(_webout) The fileref to which to write the JSON @param [out] fref= (_webout) The fileref to which to write the JSON
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
@version 9.3 @version 9.3
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); %macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug %global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables; sasjs_tables;
%local i tempds jsonengine; %local i tempds jsonengine;
@@ -16385,7 +16424,7 @@ run;
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=&jsonengine,dbg=%str(&_debug) ,engine=&jsonengine,missing=&missing
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;
@@ -16609,11 +16648,13 @@ run;
%ms_webout(CLOSE) %ms_webout(CLOSE)
@param action Either FETCH, OPEN, ARR, OBJ or CLOSE @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
@param ds The dataset to send back to the frontend @param [in] ds The dataset to send back to the frontend
@param dslabel= value to use instead of the real name for sending to JSON @param [out] dslabel= value to use instead of table name for sending to JSON
@param fmt=(Y) Set to N to send back unformatted values @param [in] fmt= (Y) Set to N to send back unformatted values
@param fref=(_webout) The fileref to which to write the JSON @param [out] fref= (_webout) The fileref to which to write the JSON
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_jsonout.sas @li mp_jsonout.sas
@@ -16628,7 +16669,7 @@ run;
**/ **/
%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y); %macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug %global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables; sasjs_tables;
@@ -16680,7 +16721,7 @@ run;
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,dbg=%str(&_debug) ,engine=DATASTEP,missing=&missing
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;
@@ -17552,9 +17593,9 @@ run;
that location that location
@param [in] adapter= the macro uses the sasjs adapter by default. To use @param [in] adapter= the macro uses the sasjs adapter by default. To use
another adapter, add a (different) fileref here. another adapter, add a (different) fileref here.
@param [in] contextname= Choose a specific context on which to run the Job. Leave @param [in] contextname= Choose a specific context on which to run the Job.
blank to use the default context. From Viya 3.5 it is possible to configure Leave blank to use the default context. From Viya 3.5 it is possible to
a shared context - see configure a shared context - see
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
@param [in] mdebug=(0) set to 1 to enable DEBUG messages @param [in] mdebug=(0) set to 1 to enable DEBUG messages
@@ -17735,9 +17776,11 @@ data _null_;
put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */"; put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */";
/* WEBOUT BEGIN */ /* WEBOUT BEGIN */
put ' '; put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP,dbg=0 '; put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP ';
put ' ,dbg=0 /* DEPRECATED */ ';
put ' ,missing=NULL ';
put ')/*/STORE SOURCE*/; '; put ')/*/STORE SOURCE*/; ';
put '%put output location=&jref; '; put '%put &sysmacroname: output location=&jref; ';
put '%if &action=OPEN %then %do; '; put '%if &action=OPEN %then %do; ';
put ' options nobomfile; '; put ' options nobomfile; ';
put ' data _null_;file &jref encoding=''utf-8'' ; '; put ' data _null_;file &jref encoding=''utf-8'' ; ';
@@ -17750,10 +17793,16 @@ data _null_;
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' '; put ' ';
put ' %if &engine=PROCJSON %then %do; '; put ' %if &engine=PROCJSON %then %do; ';
put ' %if &missing=STRING %then %do; ';
put ' %put &sysmacroname: Special Missings are not supported in proc json.; ';
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; ';
put ' %end; ';
put ' data;run;%let tempds=&syslast; '; put ' data;run;%let tempds=&syslast; ';
put ' proc sql;drop table &tempds; '; put ' proc sql;drop table &tempds; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds /view=&tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
@@ -17761,6 +17810,7 @@ data _null_;
put ' proc sql;drop view &tempds; '; put ' proc sql;drop view &tempds; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: ';
put ' %local cols i tempds; '; put ' %local cols i tempds; ';
put ' %let cols=0; '; put ' %let cols=0; ';
put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; '; put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; ';
@@ -17841,7 +17891,15 @@ data _null_;
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' proc format; /* credit yabwon for special null removal */ '; put ' proc format; /* credit yabwon for special null removal */ ';
put ' value bart ._ - .z = null '; put ' value bart ';
put ' %if &missing=NULL %then %do; ';
put ' ._ - .z = null ';
put ' %end; ';
put ' %else %do; ';
put ' ._ = [quote()] ';
put ' . = null ';
put ' .a - .z = [quote()] ';
put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ '; put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ ';
@@ -17909,7 +17967,7 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%mend mp_jsonout; '; put '%mend mp_jsonout; ';
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y); '; put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL); ';
put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name '; put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name ';
put ' sasjs_tables SYS_JES_JOB_URI; '; put ' sasjs_tables SYS_JES_JOB_URI; ';
put '%if %index("&_debug",log) %then %let _debug=131; '; put '%if %index("&_debug",log) %then %let _debug=131; ';
@@ -18036,7 +18094,7 @@ data _null_;
put '%end; '; put '%end; ';
put '%else %if &action=ARR or &action=OBJ %then %do; '; put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt '; put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
put ' ,jref=&fref,engine=DATASTEP,dbg=%str(&_debug) '; put ' ,jref=&fref,engine=DATASTEP,missing=&missing ';
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
@@ -18127,8 +18185,8 @@ data _null_;
put '%global __program _program;'; put '%global __program _program;';
put '%let _program=%sysfunc(coalescec(&__program,&_program));'; put '%let _program=%sysfunc(coalescec(&__program,&_program));';
put ' '; put ' ';
put '%macro webout(action,ds,dslabel=,fmt=);'; put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL);';
put ' %mv_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt)'; put ' %mv_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing)';
put '%mend;'; put '%mend;';
run; run;
@@ -21741,13 +21799,15 @@ filename &fref1 clear;
%mv_webout(CLOSE) %mv_webout(CLOSE)
@param action Either OPEN, ARR, OBJ or CLOSE @param [in] action Either OPEN, ARR, OBJ or CLOSE
@param ds The dataset to send back to the frontend @param [in] ds The dataset to send back to the frontend
@param _webout= fileref for returning the json @param [in] _webout= fileref for returning the json
@param fref=(_mvwtemp) Temp fileref to which to write the output @param [out] fref=(_mvwtemp) Temp fileref to which to write the output
@param dslabel= value to use instead of the real name for sending to JSON @param [out] dslabel= value to use instead of table name for sending to JSON
@param fmt=(Y) change to N to strip formats from output @param [in] fmt=(Y) change to N to strip formats from output
@param stream=(Y) Change to N if not streaming to _webout @param [in] stream=(Y) Change to N if not streaming to _webout
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_jsonout.sas @li mp_jsonout.sas
@@ -21757,7 +21817,7 @@ filename &fref1 clear;
@author Allan Bowe, source: https://github.com/sasjs/core @author Allan Bowe, source: https://github.com/sasjs/core
**/ **/
%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y); %macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL);
%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name %global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name
sasjs_tables SYS_JES_JOB_URI; sasjs_tables SYS_JES_JOB_URI;
%if %index("&_debug",log) %then %let _debug=131; %if %index("&_debug",log) %then %let _debug=131;
@@ -21884,7 +21944,7 @@ filename &fref1 clear;
%end; %end;
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
,jref=&fref,engine=DATASTEP,dbg=%str(&_debug) ,jref=&fref,engine=DATASTEP,missing=&missing
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;

View File

@@ -110,8 +110,8 @@
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG; %if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
%else %let logloc=%qsysfunc(getoption(LOG)); %else %let logloc=%qsysfunc(getoption(LOG));
proc printto log=log;run; proc printto log=log;run;
%if %length(&logloc)>0 %then %do;
%let logline=0; %let logline=0;
%if %length(&logloc)>0 %then %do;
data _null_; data _null_;
infile &logloc lrecl=5000; infile &logloc lrecl=5000;
input; putlog _infile_; input; putlog _infile_;
@@ -160,7 +160,10 @@
file _webout mod lrecl=32000 encoding='utf-8'; file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 ; length msg $32767 ;
sasdatetime=datetime(); sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg')); msg=symget('msg');
%if &logline>0 %then %do;
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
%end;
/* escape the quotes */ /* escape the quotes */
msg=tranwrd(msg,'"','\"'); msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */ /* ditch the CRLFs as chrome complains */

View File

@@ -142,16 +142,16 @@ run;
proc sql noprint; proc sql noprint;
select distinct lib into: liblist separated by ' ' from &inds; select distinct lib into: liblist separated by ' ' from &inds;
%put &=liblist; %put &=liblist;
%do i=1 %to %sysfunc(countw(&liblist)); %if %length(&liblist)>0 %then %do i=1 %to %sysfunc(countw(&liblist));
%let lib=%scan(&liblist,1); %let lib=%scan(&liblist,1);
%let engine=%mf_getengine(&lib); %let engine=%mf_getengine(&lib);
%if &engine ne V9 and &engine ne BASE %then %do; %if &engine ne V9 and &engine ne BASE %then %do;
%let msg=&lib has &engine engine - formats cannot be applied; %let msg=&lib has &engine engine - formats cannot be applied;
proc sql;
insert into &outds set lib="&lib",ds="_all_",var="_all", msg="&msg" ; insert into &outds set lib="&lib",ds="_all_",var="_all", msg="&msg" ;
%if &errds=0 %then %put %str(ERR)OR: &msg; %if &errds=0 %then %put %str(ERR)OR: &msg;
%end; %end;
%end; %end;
quit;
%if %mf_nobs(&outds)>0 %then %return; %if %mf_nobs(&outds)>0 %then %return;

View File

@@ -14,11 +14,11 @@
@param ds The dataset from which to obtain column metadata @param ds The dataset from which to obtain column metadata
@param outds= (work.cols) The output dataset to create. Sample data: @param outds= (work.cols) The output dataset to create. Sample data:
|NAME $|LENGTH 8|VARNUM 8|LABEL $|FORMAT $49|TYPE $1 |DDTYPE $| |NAME:$32.|LENGTH:best.|VARNUM:best.|LABEL:$256.|FMTNAME:$32.|FORMAT:$49.|TYPE:$1.|DDTYPE:$9.|
|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|---|
|AIR|8|2|international airline travel (thousands)|8.|N|NUMERIC| |`AIR `|`8 `|`2 `|`international airline travel (thousands) `|` `|`8. `|`N `|`NUMERIC `|
|DATE|8|1|DATE|MONYY.|N|DATE| |`DATE `|`8 `|`1 `|`DATE `|`MONYY `|`MONYY. `|`N `|`DATE `|
|REGION|3|3|REGION|$3.|C|CHARACTER| |`REGION `|`3 `|`3 `|`REGION `|` `|`$3. `|`C `|`CHARACTER `|
<h4> Related Macros </h4> <h4> Related Macros </h4>
@li mf_getvarlist.sas @li mf_getvarlist.sas
@@ -30,26 +30,27 @@
**/ **/
%macro mp_getcols(ds, outds=work.cols); %macro mp_getcols(ds, outds=work.cols);
%local dropds;
proc contents noprint data=&ds proc contents noprint data=&ds
out=_data_ (keep=name type length label varnum format:); out=_data_ (keep=name type length label varnum format:);
run; run;
data &outds(keep=name type length varnum format label ddtype); %let dropds=&syslast;
set &syslast(rename=(format=format2 type=type2)); data &outds(keep=name type length varnum format label ddtype fmtname);
set &dropds(rename=(format=fmtname type=type2));
name=upcase(name); name=upcase(name);
if type2=2 then do; if type2=2 then do;
length format $49.; length format $49.;
if format2='' then format=cats('$',length,'.'); if fmtname='' then format=cats('$',length,'.');
else if formatl=0 then format=cats(format2,'.'); else if formatl=0 then format=cats(fmtname,'.');
else format=cats(format2,formatl,'.'); else format=cats(fmtname,formatl,'.');
type='C'; type='C';
ddtype='CHARACTER'; ddtype='CHARACTER';
end; end;
else do; else do;
if format2='' then format=cats(length,'.'); if fmtname='' then format=cats(length,'.');
else if formatl=0 then format=cats(format2,'.'); else if formatl=0 then format=cats(fmtname,'.');
else if formatd=0 then format=cats(format2,formatl,'.'); else if formatd=0 then format=cats(fmtname,formatl,'.');
else format=cats(format2,formatl,'.',formatd); else format=cats(fmtname,formatl,'.',formatd);
type='N'; type='N';
if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME'; if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME';
else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY' else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
@@ -61,5 +62,6 @@ data &outds(keep=name type length varnum format label ddtype);
end; end;
if label='' then label=name; if label='' then label=name;
run; run;
proc sql;
drop table &dropds;
%mend mp_getcols; %mend mp_getcols;

View File

@@ -31,22 +31,20 @@
[sasjs adapter](https://github.com/sasjs/adapter). [sasjs adapter](https://github.com/sasjs/adapter).
For more information see https://sasjs.io For more information see https://sasjs.io
@param action Valid values: @param [in] action Valid values:
@li OPEN - opens the JSON @li OPEN - opens the JSON
@li OBJ - sends a table with each row as an object @li OBJ - sends a table with each row as an object
@li ARR - sends a table with each row in an array @li ARR - sends a table with each row in an array
@li CLOSE - closes the JSON @li CLOSE - closes the JSON
@param [in] ds The dataset to send. Must be a work table.
@param ds the dataset to send. Must be a work table. @param [out] jref= (_webout) The fileref to which to send the JSON
@param jref= the fileref to which to send the JSON @param [out] dslabel= The name to give the table in the exported JSON
@param dslabel= the name to give the table in the exported JSON @param [in] fmt= (Y) Whether to keep (Y) or strip (N) formats from the table
@param fmt= Whether to keep or strip formats from the table @param [in] engine= (DATASTEP) Which engine to use to send the JSON. Options:
@param engine= Which engine to use to send the JSON, valid options are:
@li PROCJSON (default) @li PROCJSON (default)
@li DATASTEP (more reliable when data has non standard characters) @li DATASTEP (more reliable when data has non standard characters)
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
@param dbg= DEPRECATED - was used to conditionally add PRETTY to (eg `null`) or as STRING values (eg `".a"` or `".b"`)
proc json but this can cause line truncation in large files.
<h4> Related Macros <h4> <h4> Related Macros <h4>
@li mp_ds2fmtds.sas @li mp_ds2fmtds.sas
@@ -57,9 +55,11 @@
**/ **/
%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP,dbg=0 %macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP
,dbg=0 /* DEPRECATED */
,missing=NULL
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%put output location=&jref; %put &sysmacroname: output location=&jref;
%if &action=OPEN %then %do; %if &action=OPEN %then %do;
options nobomfile; options nobomfile;
data _null_;file &jref encoding='utf-8' ; data _null_;file &jref encoding='utf-8' ;
@@ -72,10 +72,16 @@
put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":";
%if &engine=PROCJSON %then %do; %if &engine=PROCJSON %then %do;
%if &missing=STRING %then %do;
%put &sysmacroname: Special Missings are not supported in proc json.;
%put &sysmacroname: Switching to DATASTEP engine;
%goto datastep;
%end;
data;run;%let tempds=&syslast; data;run;%let tempds=&syslast;
proc sql;drop table &tempds; proc sql;drop table &tempds;
data &tempds /view=&tempds;set &ds; data &tempds /view=&tempds;set &ds;
%if &fmt=N %then format _numeric_ best32.;; %if &fmt=N %then format _numeric_ best32.;;
/* PRETTY is necessary to avoid line truncation in large files */
proc json out=&jref pretty proc json out=&jref pretty
%if &action=ARR %then nokeys ; %if &action=ARR %then nokeys ;
;export &tempds / nosastags fmtnumeric; ;export &tempds / nosastags fmtnumeric;
@@ -83,6 +89,7 @@
proc sql;drop view &tempds; proc sql;drop view &tempds;
%end; %end;
%else %if &engine=DATASTEP %then %do; %else %if &engine=DATASTEP %then %do;
%datastep:
%local cols i tempds; %local cols i tempds;
%let cols=0; %let cols=0;
%if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do;
@@ -163,7 +170,15 @@
run; run;
proc format; /* credit yabwon for special null removal */ proc format; /* credit yabwon for special null removal */
value bart ._ - .z = null value bart
%if &missing=NULL %then %do;
._ - .z = null
%end;
%else %do;
._ = [quote()]
. = null
.a - .z = [quote()]
%end;
other = [best.]; other = [best.];
data;run; %let tempds=&syslast; /* temp table for spesh char management */ data;run; %let tempds=&syslast; /* temp table for spesh char management */

View File

@@ -89,9 +89,11 @@ data _null_;
put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */"; put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */";
/* WEBOUT BEGIN */ /* WEBOUT BEGIN */
put ' '; put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP,dbg=0 '; put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP ';
put ' ,dbg=0 /* DEPRECATED */ ';
put ' ,missing=NULL ';
put ')/*/STORE SOURCE*/; '; put ')/*/STORE SOURCE*/; ';
put '%put output location=&jref; '; put '%put &sysmacroname: output location=&jref; ';
put '%if &action=OPEN %then %do; '; put '%if &action=OPEN %then %do; ';
put ' options nobomfile; '; put ' options nobomfile; ';
put ' data _null_;file &jref encoding=''utf-8'' ; '; put ' data _null_;file &jref encoding=''utf-8'' ; ';
@@ -104,10 +106,16 @@ data _null_;
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' '; put ' ';
put ' %if &engine=PROCJSON %then %do; '; put ' %if &engine=PROCJSON %then %do; ';
put ' %if &missing=STRING %then %do; ';
put ' %put &sysmacroname: Special Missings are not supported in proc json.; ';
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; ';
put ' %end; ';
put ' data;run;%let tempds=&syslast; '; put ' data;run;%let tempds=&syslast; ';
put ' proc sql;drop table &tempds; '; put ' proc sql;drop table &tempds; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds /view=&tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
@@ -115,6 +123,7 @@ data _null_;
put ' proc sql;drop view &tempds; '; put ' proc sql;drop view &tempds; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: ';
put ' %local cols i tempds; '; put ' %local cols i tempds; ';
put ' %let cols=0; '; put ' %let cols=0; ';
put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; '; put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; ';
@@ -195,7 +204,15 @@ data _null_;
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' proc format; /* credit yabwon for special null removal */ '; put ' proc format; /* credit yabwon for special null removal */ ';
put ' value bart ._ - .z = null '; put ' value bart ';
put ' %if &missing=NULL %then %do; ';
put ' ._ - .z = null ';
put ' %end; ';
put ' %else %do; ';
put ' ._ = [quote()] ';
put ' . = null ';
put ' .a - .z = [quote()] ';
put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ '; put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ ';
@@ -263,7 +280,7 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%mend mp_jsonout; '; put '%mend mp_jsonout; ';
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); '; put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug '; put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; '; put ' sasjs_tables; ';
put '%local i tempds jsonengine; '; put '%local i tempds jsonengine; ';
@@ -328,7 +345,7 @@ data _null_;
put ' '; put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; '; put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref '; put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=&jsonengine,dbg=%str(&_debug) '; put ' ,engine=&jsonengine,missing=&missing ';
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
@@ -418,8 +435,8 @@ data _null_;
put ' '; put ' ';
put '%mend mf_getuser; '; put '%mend mf_getuser; ';
/* WEBOUT END */ /* WEBOUT END */
put '%macro webout(action,ds,dslabel=,fmt=);'; put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL);';
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt)'; put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing)';
put '%mend;'; put '%mend;';
run; run;

View File

@@ -23,17 +23,19 @@
%mm_webout(CLOSE) %mm_webout(CLOSE)
@param action Either FETCH, OPEN, ARR, OBJ or CLOSE @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
@param ds The dataset to send back to the frontend @param [in] ds The dataset to send back to the frontend
@param dslabel= value to use instead of the real name for sending to JSON @param [out] dslabel= Value to use instead of table name for sending to JSON
@param fmt=(Y) Set to N to send back unformatted values @param [in] fmt=(Y) Set to N to send back unformatted values
@param fref=(_webout) The fileref to which to write the JSON @param [out] fref= (_webout) The fileref to which to write the JSON
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
@version 9.3 @version 9.3
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); %macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug %global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables; sasjs_tables;
%local i tempds jsonengine; %local i tempds jsonengine;
@@ -98,7 +100,7 @@
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=&jsonengine,dbg=%str(&_debug) ,engine=&jsonengine,missing=&missing
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sasjs/core", "name": "@sasjs/core",
"description": "Production Ready Macros for SAS Application Developers", "description": "Macros for SAS Application Developers",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
"SAS", "SAS",

View File

@@ -1,15 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- HTML header for doxygen 1.8.17--> <!-- HTML header for doxygen 1.8.17-->
<html xmlns="https://www.w3.org/1999/xhtml" lang="en"> <html xmlns="https://www.w3.org/1999/xhtml" lang="en">
<head>
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=9" /> <meta http-equiv="X-UA-Compatible" content="IE=9" />
<meta property="og:type" content="website"> <meta property="og:type" content="website">
<meta property="og:title" content="MacroCore" />
<meta property="og:url" content="https://core.sasjs.io" />
<meta property="og:image" content="https://core.sasjs.io/Macro_core_website_1.png" />
<meta name="author" content="Allan Bowe"> <meta name="author" content="Allan Bowe">
<meta name="generator" content="Doxygen $doxygenversion" /> <meta name="generator" content="Doxygen $doxygenversion" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<!--BEGIN PROJECT_NAME--> <!--BEGIN PROJECT_NAME-->
<meta name="description" content="$projectbrief" /> <meta name="description" content="$projectbrief" />
<meta name="og:description" content="$projectbrief" />
<!--END PROJECT_NAME--> <!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--> <!--BEGIN !PROJECT_NAME-->
<title>$title</title> <title>$title</title>
@@ -21,8 +27,9 @@
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" /> <link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" />
$extrastylesheet $extrastylesheet
</head> </head>
<body>
<body>
<div id="top"> <div id="top">
<!-- do not remove this div, it is closed by doxygen! --> <!-- do not remove this div, it is closed by doxygen! -->
@@ -33,14 +40,12 @@
<tr style="height: 56px"> <tr style="height: 56px">
<!--BEGIN PROJECT_LOGO--> <!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"> <td id="projectlogo">
<a href="$relpath^" <a href="$relpath^"><img alt="Logo" src="$relpath^$projectlogo" /></a>
><img alt="Logo" src="$relpath^$projectlogo"
/></a>
</td> </td>
<!--END PROJECT_LOGO--> <!--END PROJECT_LOGO-->
<td id="projectalign" style="padding-left: 0.5em"> <td id="projectalign" style="padding-left: 0.5em">
<div id="projectbrief"> <div id="projectbrief">
Production Ready Macros for SAS Application Developers<br /> Macros for SAS Application Developers<br />
<a href="https://github.com/sasjs/core"> <a href="https://github.com/sasjs/core">
https://github.com/sasjs/core https://github.com/sasjs/core
</a> </a>
@@ -63,5 +68,6 @@
<!--END TITLEAREA--> <!--END TITLEAREA-->
<!-- end header part --> <!-- end header part -->
</div> </div>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,5 @@
{ {
"$schema": "https://cli.sasjs.io/sasjsconfig-schema.json", "$schema": "https://raw.githubusercontent.com/sasjs/utils/main/src/types/sasjsconfig-schema.json",
"macroFolders": [ "macroFolders": [
"base", "base",
"fcmp", "fcmp",

View File

@@ -20,11 +20,13 @@
%ms_webout(CLOSE) %ms_webout(CLOSE)
@param action Either FETCH, OPEN, ARR, OBJ or CLOSE @param [in] action Either FETCH, OPEN, ARR, OBJ or CLOSE
@param ds The dataset to send back to the frontend @param [in] ds The dataset to send back to the frontend
@param dslabel= value to use instead of the real name for sending to JSON @param [out] dslabel= value to use instead of table name for sending to JSON
@param fmt=(Y) Set to N to send back unformatted values @param [in] fmt= (Y) Set to N to send back unformatted values
@param fref=(_webout) The fileref to which to write the JSON @param [out] fref= (_webout) The fileref to which to write the JSON
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_jsonout.sas @li mp_jsonout.sas
@@ -39,7 +41,7 @@
**/ **/
%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y); %macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug %global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables; sasjs_tables;
@@ -91,7 +93,7 @@
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,dbg=%str(&_debug) ,engine=DATASTEP,missing=&missing
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;

View File

@@ -4,6 +4,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_getcols.sas @li mp_getcols.sas
@li mp_assertcols.sas
@li mp_assertcolvals.sas @li mp_assertcolvals.sas
@li mp_assertdsobs.sas @li mp_assertdsobs.sas
@@ -31,3 +32,9 @@ run;
desc=All values have a match, desc=All values have a match,
test=ALLVALS test=ALLVALS
) )
%mp_assertcols(work.info,
cols=name type length varnum format label ddtype fmtname,
test=ALL,
desc=check all columns exist
)

View File

@@ -34,6 +34,11 @@ data work.test;
call symputx('dtval',dtval); call symputx('dtval',dtval);
run; run;
%mp_assert(
iftrue=(&syscc=0),
desc=Checking for error condition,
outds=work.test_results
)
%mp_assert( %mp_assert(
iftrue=(&dtval=&compare), iftrue=(&dtval=&compare),

View File

@@ -0,0 +1,52 @@
/**
@file
@brief Testing mp_jsonout.sas macro with special missings
<h4> SAS Macros </h4>
@li mp_jsonout.sas
@li mp_assert.sas
**/
filename webref temp;
data demo;
do x=._,.,.a,.b,.c,.d,.e,-99, 0, 1,2, 3.333333;
output;
end;
run;
%mp_jsonout(OPEN,jref=webref)
%mp_jsonout(OBJ,demo,jref=webref,fmt=N,missing=STRING)
%mp_jsonout(CLOSE,jref=webref)
data _null_;
infile webref;
input;
putlog _infile_;
run;
libname web JSON fileref=webref;
/* proc json turns to char - so switch back to numeric */
data work.test(keep=x);
set web.demo(rename=(x=y));
if y ='_' then x=._;
else if anyalpha(y) then x=input(cats(".",y),best.);
else x=input(y,best.);
put (_all_)(=);
run;
%mp_assert(
iftrue=(&syscc=0),
desc=Checking for error condition with special missing export,
outds=work.test_results
)
proc compare base=work.demo compare=work.test;
quit;
%mp_assert(
iftrue=(&sysinfo=0),
desc=Returned json is identical to input table for all special missings,
outds=work.test_results
)

View File

@@ -54,9 +54,9 @@
that location that location
@param [in] adapter= the macro uses the sasjs adapter by default. To use @param [in] adapter= the macro uses the sasjs adapter by default. To use
another adapter, add a (different) fileref here. another adapter, add a (different) fileref here.
@param [in] contextname= Choose a specific context on which to run the Job. Leave @param [in] contextname= Choose a specific context on which to run the Job.
blank to use the default context. From Viya 3.5 it is possible to configure Leave blank to use the default context. From Viya 3.5 it is possible to
a shared context - see configure a shared context - see
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
@param [in] mdebug=(0) set to 1 to enable DEBUG messages @param [in] mdebug=(0) set to 1 to enable DEBUG messages
@@ -237,9 +237,11 @@ data _null_;
put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */"; put "/* Created on %sysfunc(datetime(),datetime19.) by &sysuserid */";
/* WEBOUT BEGIN */ /* WEBOUT BEGIN */
put ' '; put ' ';
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP,dbg=0 '; put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y,engine=DATASTEP ';
put ' ,dbg=0 /* DEPRECATED */ ';
put ' ,missing=NULL ';
put ')/*/STORE SOURCE*/; '; put ')/*/STORE SOURCE*/; ';
put '%put output location=&jref; '; put '%put &sysmacroname: output location=&jref; ';
put '%if &action=OPEN %then %do; '; put '%if &action=OPEN %then %do; ';
put ' options nobomfile; '; put ' options nobomfile; ';
put ' data _null_;file &jref encoding=''utf-8'' ; '; put ' data _null_;file &jref encoding=''utf-8'' ; ';
@@ -252,10 +254,16 @@ data _null_;
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; '; put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
put ' '; put ' ';
put ' %if &engine=PROCJSON %then %do; '; put ' %if &engine=PROCJSON %then %do; ';
put ' %if &missing=STRING %then %do; ';
put ' %put &sysmacroname: Special Missings are not supported in proc json.; ';
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
put ' %goto datastep; ';
put ' %end; ';
put ' data;run;%let tempds=&syslast; '; put ' data;run;%let tempds=&syslast; ';
put ' proc sql;drop table &tempds; '; put ' proc sql;drop table &tempds; ';
put ' data &tempds /view=&tempds;set &ds; '; put ' data &tempds /view=&tempds;set &ds; ';
put ' %if &fmt=N %then format _numeric_ best32.;; '; put ' %if &fmt=N %then format _numeric_ best32.;; ';
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
put ' proc json out=&jref pretty '; put ' proc json out=&jref pretty ';
put ' %if &action=ARR %then nokeys ; '; put ' %if &action=ARR %then nokeys ; ';
put ' ;export &tempds / nosastags fmtnumeric; '; put ' ;export &tempds / nosastags fmtnumeric; ';
@@ -263,6 +271,7 @@ data _null_;
put ' proc sql;drop view &tempds; '; put ' proc sql;drop view &tempds; ';
put ' %end; '; put ' %end; ';
put ' %else %if &engine=DATASTEP %then %do; '; put ' %else %if &engine=DATASTEP %then %do; ';
put ' %datastep: ';
put ' %local cols i tempds; '; put ' %local cols i tempds; ';
put ' %let cols=0; '; put ' %let cols=0; ';
put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; '; put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 %then %do; ';
@@ -343,7 +352,15 @@ data _null_;
put ' run; '; put ' run; ';
put ' '; put ' ';
put ' proc format; /* credit yabwon for special null removal */ '; put ' proc format; /* credit yabwon for special null removal */ ';
put ' value bart ._ - .z = null '; put ' value bart ';
put ' %if &missing=NULL %then %do; ';
put ' ._ - .z = null ';
put ' %end; ';
put ' %else %do; ';
put ' ._ = [quote()] ';
put ' . = null ';
put ' .a - .z = [quote()] ';
put ' %end; ';
put ' other = [best.]; '; put ' other = [best.]; ';
put ' '; put ' ';
put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ '; put ' data;run; %let tempds=&syslast; /* temp table for spesh char management */ ';
@@ -411,7 +428,7 @@ data _null_;
put ' run; '; put ' run; ';
put '%end; '; put '%end; ';
put '%mend mp_jsonout; '; put '%mend mp_jsonout; ';
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y); '; put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL); ';
put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name '; put '%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name ';
put ' sasjs_tables SYS_JES_JOB_URI; '; put ' sasjs_tables SYS_JES_JOB_URI; ';
put '%if %index("&_debug",log) %then %let _debug=131; '; put '%if %index("&_debug",log) %then %let _debug=131; ';
@@ -538,7 +555,7 @@ data _null_;
put '%end; '; put '%end; ';
put '%else %if &action=ARR or &action=OBJ %then %do; '; put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt '; put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt ';
put ' ,jref=&fref,engine=DATASTEP,dbg=%str(&_debug) '; put ' ,jref=&fref,engine=DATASTEP,missing=&missing ';
put ' ) '; put ' ) ';
put '%end; '; put '%end; ';
put '%else %if &action=CLOSE %then %do; '; put '%else %if &action=CLOSE %then %do; ';
@@ -629,8 +646,8 @@ data _null_;
put '%global __program _program;'; put '%global __program _program;';
put '%let _program=%sysfunc(coalescec(&__program,&_program));'; put '%let _program=%sysfunc(coalescec(&__program,&_program));';
put ' '; put ' ';
put '%macro webout(action,ds,dslabel=,fmt=);'; put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL);';
put ' %mv_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt)'; put ' %mv_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing)';
put '%mend;'; put '%mend;';
run; run;

View File

@@ -20,13 +20,15 @@
%mv_webout(CLOSE) %mv_webout(CLOSE)
@param action Either OPEN, ARR, OBJ or CLOSE @param [in] action Either OPEN, ARR, OBJ or CLOSE
@param ds The dataset to send back to the frontend @param [in] ds The dataset to send back to the frontend
@param _webout= fileref for returning the json @param [in] _webout= fileref for returning the json
@param fref=(_mvwtemp) Temp fileref to which to write the output @param [out] fref=(_mvwtemp) Temp fileref to which to write the output
@param dslabel= value to use instead of the real name for sending to JSON @param [out] dslabel= value to use instead of table name for sending to JSON
@param fmt=(Y) change to N to strip formats from output @param [in] fmt=(Y) change to N to strip formats from output
@param stream=(Y) Change to N if not streaming to _webout @param [in] stream=(Y) Change to N if not streaming to _webout
@param [in] missing= (NULL) Special numeric missing values can be sent as NULL
(eg `null`) or as STRING values (eg `".a"` or `".b"`)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_jsonout.sas @li mp_jsonout.sas
@@ -36,7 +38,7 @@
@author Allan Bowe, source: https://github.com/sasjs/core @author Allan Bowe, source: https://github.com/sasjs/core
**/ **/
%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y); %macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL);
%global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name %global _webin_file_count _webin_fileuri _debug _omittextlog _webin_name
sasjs_tables SYS_JES_JOB_URI; sasjs_tables SYS_JES_JOB_URI;
%if %index("&_debug",log) %then %let _debug=131; %if %index("&_debug",log) %then %let _debug=131;
@@ -163,7 +165,7 @@
%end; %end;
%else %if &action=ARR or &action=OBJ %then %do; %else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt
,jref=&fref,engine=DATASTEP,dbg=%str(&_debug) ,jref=&fref,engine=DATASTEP,missing=&missing
) )
%end; %end;
%else %if &action=CLOSE %then %do; %else %if &action=CLOSE %then %do;