crfData.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. //not tested yet.
  2. //to use, add crfTecant/crfData.js to requiresScript and in the call-back, run init
  3. //will work with crfSetup as setup object
  4. var crfData={};
  5. crfData.init=
  6. function(cb=null){
  7. this.print('[crfData:init]');
  8. let that=this;
  9. let action=function(){that.afterScripts(cb);};
  10. LABKEY.requiresScript(["crf/runQuery.js","crf/variableList.js"],action);
  11. }
  12. crfData.afterScripts=
  13. function(cb=null){
  14. if (cb) cb();
  15. }
  16. crfData.setSetup=
  17. function(setup){
  18. this.setup=setup;
  19. }
  20. crfData.getContainer=
  21. function(label){
  22. return this.setup.getContainer(label);
  23. }
  24. crfData.print=
  25. function(msg){
  26. console.log(msg);
  27. }
  28. //getters
  29. crfData.getSnapshotObject=
  30. function(){
  31. if (!("dataQueriesSnapshot" in this))
  32. this.dataQueriesSnapshot=new Object();
  33. return this.dataQueriesSnapshot;
  34. }
  35. crfData.getQuerySnapshot=
  36. function(queryName){
  37. //check whether queryName is in snapshotObject?
  38. return this.getSnapshotObject()[queryName];
  39. }
  40. crfData.getLayoutObject=
  41. function(){
  42. if (!("dataQueriesLayout" in this))
  43. this.dataQueriesLayout=new Object();
  44. return this.dataQueriesLayout;
  45. }
  46. crfData.getQueryLayout=
  47. function(queryName){
  48. //check whether queryName is in snapshotObject?
  49. return this.getLayoutObject()[queryName];
  50. }
  51. crfData.getLookupObject=
  52. function(){
  53. if (!("lookup" in this))
  54. this.lookup=new Object();
  55. return this.lookup;
  56. }
  57. crfData.getLookup=
  58. function(queryName){
  59. let x=this.getLookupObject();
  60. if (queryName in x) return x[queryName];
  61. return null;
  62. }
  63. crfData.getRegistration=
  64. function(){
  65. let fName='[getRegistration]';
  66. let regQueryPars=variableList.parseVariables(this.setup.getSettings('registrationQuery'));
  67. let query=regQueryPars['query'];
  68. this.print(fName+' query '+query);
  69. return this.getQuerySnapshot(query).rows;
  70. }
  71. crfData.getCrfEntry=
  72. function(){
  73. return this.getQuerySnapshot('crfEntry').rows[0];
  74. }
  75. crfData.getActiveQueries=
  76. function(){
  77. if (!("activeQueries" in this))
  78. this.activeQueries=new Object();
  79. return this.activeQueries;
  80. }
  81. crfData.getActiveQuery=
  82. function(queryName){
  83. let aq=this.getActiveQueries();
  84. if (queryName in aq) return aq[queryName];
  85. return null;
  86. }
  87. crfData.getRegistrationMap=
  88. function(value=null){
  89. let rows=this.getRegistration();
  90. let qMap=new Object();
  91. let key='Key';
  92. if (!value) value='participantStudyId';
  93. for (let i=0;i<rows.length;i++){
  94. qMap[rows[i][key]]=rows[i][value];
  95. }
  96. return qMap;
  97. }
  98. crfData.getRegistrationEntryMap=
  99. function(key=null){
  100. let rows=this.getRegistration();
  101. let qMap=new Object();
  102. if (!key) key='Key';
  103. for (let i=0;i<rows.length;i++){
  104. qMap[rows[i][key]]=rows[i];
  105. }
  106. return qMap;
  107. }
  108. crfData.getCrfRefForData=
  109. function(){
  110. let parentCrf=this.getCrfEntry()['parentCrf'];
  111. if (!parentCrf) return this.getCrfEntry()['entryId'];
  112. return parentCrf;
  113. }
  114. crfData.setDataLayout=
  115. function(formId,role,cb){
  116. let fName='[setDataLayout]';
  117. this.print(fName);
  118. let rowsSetup=this.setup.selectFormSetupRows(formId);
  119. let queryArray=new Array();
  120. let dS=this.getLayoutObject();//reference only
  121. let qMap=this.setup.getMap('inputLists');
  122. let qMapInverse=this.setup.invertMap(qMap);
  123. this.clearActiveQueries();
  124. //config.formConfig.lookup=new Object();
  125. for (let i=0;i<rowsSetup.length;i++){
  126. let entry=rowsSetup[i];
  127. //skip review rows
  128. if (entry['showFlag']=='REVIEW')
  129. continue;
  130. let accessMode=role+'Mode';
  131. //skipField
  132. if (entry[accessMode]=="NONE") continue;
  133. let queryId=entry['queryName'];
  134. let q=qMap[queryId];
  135. queryArray.push(runQuery.makeQuery(dS,'data',q,q,[]));
  136. this.addActiveQuery(crfSetup.getEntryMap('inputLists')[queryId]);
  137. this.print(fName+' adding '+q);
  138. if (entry['showQuery']!="NONE"){
  139. let sq=entry['showQuery'];
  140. queryArray.push(runQuery.makeQuery(dS,'data',sq,sq,[]));
  141. //need inverse of qMap
  142. let sQueryId=qMapInverse[sq];
  143. this.addActiveQuery(crfSetup.getEntryMap('inputLists')[sQueryId]);
  144. this.print(fName+' adding '+sq);
  145. }
  146. }
  147. //always add reviews
  148. let q='reviewComments';
  149. queryArray.push(runQuery.makeQuery(dS,'data',q,q,[]));
  150. let rQueryId=qMapInverse[q];
  151. if (!rQueryId){
  152. this.print(fName+' missing query '+q+' in inputLists');
  153. return
  154. }
  155. this.addActiveQuery(crfSetup.getEntryMap('inputLists')[rQueryId]);
  156. //debug
  157. this.print("List of datasets in form : ");
  158. for (f in this.getActiveQueries()){
  159. let entry=this.getActiveQuery(f);
  160. this.print("\t"+f+" ID: "+entry['Key']+' title '+entry['title']);
  161. }
  162. let that=this;
  163. let action=function(){that.processLayout(cb);};
  164. runQuery.getDataFromQueries(this,queryArray,action);
  165. }
  166. //this happens after the for loop, so all dataQueries objects are set
  167. crfData.processLayout=
  168. function(cb=null){
  169. let fName='[processLayout]';
  170. let qList=this.getActiveQueries();
  171. //for layouts
  172. let queryArray=new Array();
  173. let targetObject=this.getLookupObject();
  174. let lookupSet=new Object();
  175. for (let qId in qList){
  176. let entry=this.getActiveQuery(qId);
  177. let q=entry['queryName'];
  178. let qobject=this.getQueryLayout(q);
  179. this.print(fName+" inspecting layout for "+q+" "+qobject);
  180. qobject.fields=qobject.metaData.fields;
  181. qobject.title=entry['title'];
  182. //check for lookups
  183. for (let f in qobject.fields){
  184. //anything else is simple but lookup
  185. let field=qobject.fields[f];
  186. if (!("lookup" in field)) continue;
  187. let lookup=field.lookup;
  188. let qObject=this.getLookup(lookup.queryName);
  189. if (qObject) continue;
  190. //add to list
  191. let qName=lookup.queryName;
  192. let qCode=qName+':'+lookup.keyColumn+':'+lookup.displayColumn;
  193. let e=runQuery.makeQuery(targetObject,'data',qName,qCode,[]);
  194. //adjust minor settings
  195. if (lookup.containerPath) e.containerPath=lookup.containerPath;
  196. e.schemaName=lookup.schemaName;
  197. e.columns=lookup.keyColumn+','+lookup.displayColumn;
  198. lookupSet[qCode]=e;
  199. this.print(fName+' inserting '+qCode);
  200. }
  201. }
  202. for (let x in lookupSet){
  203. queryArray.push(lookupSet[x]);
  204. this.print(fName+' adding '+x);
  205. for (let v in lookupSet[x]){
  206. this.print(fName+' value ['+v+'] '+lookupSet[x][v]);
  207. }
  208. }
  209. //this.print(fName+' print '+targetObject.print);
  210. let that=this;
  211. let action=function(){that.processLookup(cb);};
  212. this.print(fName+' getDataFromQueries');
  213. runQuery.getDataFromQueries(this,queryArray,action);
  214. this.print(fName+' getDataFromQueries done');
  215. }
  216. crfData.processLookup=
  217. function(cb=null){
  218. let fName="[processLookup]";
  219. let obj=this.getLookupObject();
  220. for (let q in obj){
  221. this.print(fName+" "+q);
  222. let a=q.split(':');
  223. if (a.length<3) continue;
  224. let lookupName=a[0];
  225. let key=a[1];
  226. let val=a[2];
  227. obj[lookupName]=new Object();
  228. this.print(fName+' adding ['+lookupName+'] '+key+'/'+val);
  229. let lObject=obj[lookupName];
  230. lObject.LUT=new Array();//key to value
  231. lObject.ValToKey=new Array();//value to key
  232. lObject.keyColumn=key
  233. lObject.displayColumn=val;
  234. let qRows=obj[q].rows;
  235. for (let i=0;i<qRows.length;i++){
  236. let r=qRows[i];
  237. this.print(fName+' LUT ['+r[key]+'] '+r[val]);
  238. lObject.LUT[r[key]]=r[val];
  239. lObject.ValToKey[r[val]]=r[key];
  240. }
  241. }
  242. if (cb) cb();
  243. }
  244. crfData.setData=
  245. function(crfRef,cb=null, schemaName=null){
  246. fName='[setData]';
  247. //let crfMatch=this.getCRFref();
  248. //let parentCrf=config.formConfig.crfEntry['parentCrf'];
  249. //if (parentCrf!=undefined) crfMatch=parentCrf;
  250. this.print(fName+' form crf ['+crfRef+'] ');
  251. let queryArray=new Array();
  252. let targetObject=this.getSnapshotObject();
  253. //collect data and execute callback cb for queries in cb.queryList
  254. let qList=this.getActiveQueries();
  255. for (let qId in qList){
  256. let entry=qList[qId];
  257. let q=entry['queryName'];
  258. let filters=[LABKEY.Filter.create("crfRef",crfRef)];
  259. let fieldName=q;
  260. if (schemaName=='study') fieldName=q+'Study';
  261. queryArray.push(runQuery.makeQuery(targetObject,'data',q,fieldName,filters,schemaName));
  262. }
  263. runQuery.getDataFromQueries(this,queryArray,cb);
  264. }
  265. crfData.setDataForQuery=
  266. function(queryName,crfRef=null,cb=null,schemaName='lists',crfField='crfRef'){
  267. let queryArray=new Array();
  268. let targetObject=this.getSnapshotObject();
  269. let filters=[LABKEY.Filter.create(crfField,crfRef)];
  270. let fieldName=q;
  271. if (schemaName=='study') fieldName=q+'Study';
  272. queryArray.push(runQuery.makeQuery(targetObject,'data',q,fieldName,filters,schemaName));
  273. runQuery.getDataFromQueries(this,queryArray,cb);
  274. }
  275. crfData.uploadData=
  276. function(id,crfRef,cb=null){
  277. let fName='[uploadData['+id+']'+crfRef+']';
  278. this.print(fName);
  279. let qList=this.getActiveQueries();
  280. let modArray=new Array();
  281. let schemaName='study';
  282. let containerName='data';
  283. for (let qId in qList){
  284. let entry=qList[qId];
  285. let q=entry['queryName'];
  286. this.print(fName+' working on '+q);
  287. //determine rows that need to be updated form querySnapshot
  288. let studyRows=this.getQuerySnapshot(q+'Study').rows;
  289. let listRows=this.getQuerySnapshot(q).rows;
  290. this.print(fName+' studies '+studyRows.length+' lists '+listRows.length);
  291. //rows to be UPDATED (already in dataset)
  292. let modRows=new Array();
  293. for (let i=0;i<studyRows.length;i++){
  294. let entry=studyRows[i];
  295. //
  296. if (! (i<listRows.length) ) continue;
  297. let entryList=listRows[i];
  298. //keeps study only variables (ParticipantId, SequenceNum)
  299. for (let f in entryList) {
  300. entry[f]=entryList[f];
  301. this.print(fName+" copying ["+f+"]: "+entry[f]+"/"+entryList[f]);
  302. }
  303. modRows.push(entry);
  304. }
  305. //rows to be INSERTED
  306. let insRows=new Array();
  307. let participantField=crfSetup.getRows('studyData')[0]["SubjectColumnName"];
  308. for (let i=studyRows.length;i<listRows.length;i++){
  309. let entry=listRows[i];
  310. //make sure you have the participantField right
  311. //
  312. entry[participantField]=id;
  313. entry.crfRef=crfRef;;
  314. entry.SequenceNum=crfRef;
  315. entry.SequenceNum=entry.SequenceNum % 1000000000;
  316. if (listRows.length>1){
  317. entry.SequenceNum+=i/100;
  318. }
  319. this.print( "Adding sequence number "+entry.SequenceNum);
  320. insRows.push(entry);
  321. }
  322. if (modRows.length>0)
  323. modArray.push(runQuery.makeModification('update',containerName,schemaName,q,modRows));
  324. //determine rows that need to be inserted from querySnapshot
  325. if (insRows.length>0)
  326. modArray.push(runQuery.makeModification('insert',containerName,schemaName,q,insRows));
  327. }
  328. //do the whole batch
  329. runQuery.modifyDataFromQueries(this,modArray,cb);
  330. }
  331. crfData.removeData=
  332. function(cb=null){
  333. let qList=this.getActiveQueries();
  334. let modArray=new Array();
  335. for (let qId in qList){
  336. let entry=qList[qId];
  337. let q=entry['queryName'];
  338. //determine rows that need to be updated form querySnapshot
  339. let studyRows=this.getQuerySnapshot(q+'Study').rows;
  340. if (studyRows.length>0)
  341. modArray.push(runQuery.makeModification('delete','data','study',q,studyRows));
  342. let listRows=this.getQuerySnapshot(q).rows;
  343. if (listRows.length>0)
  344. modArray.push(runQuery.makeModification('delete','data','lists',q,listRows));
  345. }
  346. //do the whole batch
  347. runQuery.modifyDataFromQueries(this,modArray,cb);
  348. }
  349. crfData.setRegistration=
  350. function(cb=null){
  351. let regQueryPars=variableList.parseVariables(this.setup.getSettings('registrationQuery'));
  352. let q=regQueryPars['query'];
  353. let queryArray=new Array();
  354. let targetObject=this.getSnapshotObject();
  355. let filters=[];
  356. queryArray.push(runQuery.makeQuery(targetObject,'data',q,q,filters));
  357. runQuery.getDataFromQueries(this,queryArray,cb);
  358. }
  359. crfData.setCrfEntry=
  360. function(crfRef,cb=null){
  361. let q='crfEntry';
  362. let queryArray=new Array();
  363. let targetObject=this.getSnapshotObject();
  364. let filters=[LABKEY.Filter.create('entryId',crfRef)];
  365. queryArray.push(runQuery.makeQuery(targetObject,'data',q,q,filters));
  366. runQuery.getDataFromQueries(this,queryArray,cb);
  367. }
  368. crfData.createCrfStatus=
  369. function(crfEntry){
  370. let crfStatus=new Object();
  371. crfStatus.entryId=crfEntry.entryId;
  372. crfStatus.submissionDate=new Date();
  373. crfStatus.FormStatus=crfEntry.FormStatus;
  374. crfStatus.User=crfEntry.UserId;
  375. crfStatus.Form=crfEntry.Form;
  376. return crfStatus;
  377. }
  378. crfData.addActiveQuery=
  379. function(entry){
  380. let aq=this.getActiveQueries();
  381. let qName=entry['queryName'];
  382. if (qName in aq) return;
  383. aq[qName]=entry;
  384. return;
  385. }
  386. crfData.clearActiveQueries=
  387. function(){
  388. let aq=this.getActiveQueries();
  389. for (q in aq){
  390. delete aq[q];
  391. }
  392. }