source: cprs/branches/tmg-cprs/m_files/TMGSRCH.m@ 837

Last change on this file since 837 was 796, checked in by Kevin Toppenberg, 14 years ago

Initial upload

File size: 18.4 KB
Line 
1TMGSRCH ;TMG/kst/Search API ; 6/4/10
2 ;;1.0;TMG-LIB;**1**;05/19/10
3 ;
4 ;"TMG FILEMAN SEARCH API
5 ;
6 ;"Copyright Kevin Toppenberg MD 5/19/10
7 ;"Released under GNU General Public License (GPL)
8 ;"
9 ;"NOTE: this function depends on new version of LIST^DIC, from G. Timpson Patch
10 ;"=======================================================================
11 ;" RPC -- Public Functions.
12 ;"=======================================================================
13 ;"SRCH(OUT,FILENUM,STR) --A search function, to support calls by RPC from CPRS
14 ;"BKSRCH(FILENUM,STR) -- designed to be called via JOB --> separate job thread
15 ;"FMSRCH(OUT,FILENUM,COMPEXPR) --A wrapper for Fileman search call
16 ;"=======================================================================
17 ;"PRIVATE API FUNCTIONS
18 ;"=======================================================================
19 ;"PARSESTR(FILENUM,STR,ARRAY,FNUMPTR) -- Parse user input into formatted array
20 ;"PARSE1(FILENUM,STR,FNUMPTR,ARRAY) --Parse a simple search term
21 ;"BKPGFN(MSG,PCT) -- Callable progress function code for background thread.
22 ;"DOSRCH(PTMGOUT,FILENUM,STR,PGFN) --Common search codes
23 ;"=======================================================================
24 ;"=======================================================================
25 ;"Dependencies:
26 ;" TMGDBAPI, DIE, XLFSTR, TMGSRCH0, TMGSRCH1, TMGSTUTL
27 ;"=======================================================================
28 ;"=======================================================================
29 ;
30 ;
31 ;"=======================================================================
32 ;" SEARCH STRING DOCUMENTATION
33 ;"=======================================================================
34 ;"Search string examples:
35 ;" 8925:.02(.01="SMITH,JOHN")
36 ;" 1234:.01(.03in"32..55") <-- this is a range test
37 ;" 1234:.99((.01="SMITH,JOHN") OR (.01="SMITH,BILL")) AND 4567:.01(.02'="4/2/10") NOT (1["HAPPY")
38 ;" 8925:(REPORT TEXT[DM-2)!(REPORT TEXT[HTN) AND 120.5:((VITAL TYPE=PULSE)&(RATE>70)) Targetfile=2
39 ;"
40 ;"SYNTAX:
41 ;" -- File specifier. To specify searching in a file OTHER THAN target filenumber, an optional
42 ;" FILENUM:FLD[:FLD[:FLD...]] may be specified. However, ultimately, this must point back
43 ;" to the target filenumber. E.g. Search in file 8925, but for each entry found, use the IEN
44 ;" specified by FLD (or FLDA:FLDB or FLDA:FLDB:FLDC:...). NOTE: If just FILENUM is provided
45 ;" without specifying FLD(s) to point to target filenumber, then the code will find a path
46 ;" (if possible), using first one found.
47 ;" FILENUM:(...)
48 ;" The logic is read from left to right, honoring parentheses. If a filenumber
49 ;" is not specified, then the last specified filenumber is used.
50 ;" E.g. 1234:.01( LogicA ) OR 234:.99( LogicB ) AND ( LogicC )
51 ;" LogicA fields refer to file 1234:.01.
52 ;" LogicB fields refer to file 234:.99
53 ;" LogicA fields refer to file 234:.99 (last specified file number)
54 ;" E.g. 5678:.01( (LogicA1) OR 5432:.88(LogicA2) NOT (LogicA3) ) or (LogicB)
55 ;" LogicA1 fields refer to file 5678:.01
56 ;" LogicA2 fields refer to file 5432:.88
57 ;" LogicA3 fields refer to file 5432:.88 (last specified file number inside parentheses)
58 ;" LogicB fields refer to file 5678 (last specified file number at same parentheses level)
59 ;" -- Each individual search term must be enclosed in parentheses, and may contain sub-terms
60 ;" enclosed in nested parentheses
61 ;" -- Each individual search term is comprised of:
62 ;" FIELD then COMPARATOR then VALUE
63 ;" 1. FIELDS -- can be name or number. This is for currently active file (see below)
64 ;" may also be FIELDA:FIELDB:... when FIELDA is a pointer, then FIELDB
65 ;" is taken from the pointed-to file. If FIELDB is not provided, and FIELDA
66 ;" is a pointer, then the .01 field of pointed-to-file. Individual field
67 ;" names may be inclosed in quotes
68 ;" 2. COMPARATOR -- can be:
69 ;" "=" -- means exact match
70 ;" "'=", "<>", -- any of these means Does-not-equal
71 ;" ">=", "'<" -- means greater-than-or-equal-to (same as not-less-than)
72 ;" "<=", "'>" -- means less-than-or-equal-to (same sa not-greater-than)
73 ;" "in","IN","In","{" -- means field is in specified rage (see Value below)
74 ;" When using IN, if field name is provided by NAME (not number),
75 ;" then field name should be inclosed in quotes to separate the
76 ;" letters of the field name from the letters of 'IN'.
77 ;" "[" -- means 'contains'. Interpreted as follows:
78 ;" -- For Word processor (WP) fields, this means that any line in the entire field
79 ;" can contain search term, to be matched positive.
80 ;" -- For free text field, then just text of field is searched.
81 ;" 3. VALUE -- The search term to search for. Should be in quotes.
82 ;" Note: if comparator is "IN", then syntax is "Value1..Value2"
83 ;" There should be a ".." between the two values.
84 ;" -- Logical combiners of separate search terms allowed are:
85 ;" "OR" or "|" or "||" or "!"
86 ;" "AND" or "&" or "&&"
87 ;" "NOT" or "'" or "ANDNOT"
88 ;"=======================================================================
89 ;"=======================================================================
90 ;
91 ;
92TEST ;
93 NEW STR,OUT
94 ;"SET STR="8925:(STATUS=COMPLETED)&((PATIENT[CUTSHALL)!(PATIENT[CUTSHAW))"
95 SET STR="8925:(REPORT TEXT[DM-2)!(REPORT TEXT[HTN) AND 120.5:((VITAL TYPE=PULSE)&(RATE>70))"
96 ;"SET STR="8925:(REPORT TEXT[DM-2) AND 120.5:((VITAL TYPE=PULSE)&(RATE>70))"
97 ;"SET STR="8925:(REPORT TEXT[HTN) AND 120.5:((VITAL TYPE=PULSE)&(RATE{70..75))"
98 ;"SET STR="8925:(REPORT TEXT[DM-2)!(REPORT TEXT[HTN)"
99 ;"WRITE STR,!
100 ;"DO SRCH(.OUT,2,STR)
101 ;"NEW CT SET CT=+$GET(OUT("COUNT"))
102 ;"WRITE "Found ",CT," total matches.",!
103 ;
104 DO BKSRCH(2,STR)
105 NEW STATUS,PCT
106 NEW REF SET REF=$NAME(^TMP("TMG","TMGSRCH",$J))
107 FOR DO QUIT:(STATUS["#DONE#")
108 . HANG 1
109 . SET STATUS=$GET(@REF@("MSG"))
110 . WRITE "STATUS: ",STATUS,!
111 ;"IF $DATA(@REF) ZWR @REF
112 QUIT
113 ;
114SRCH(OUT,FILENUM,STR) ;
115 ;"Purpose: A search function, to support calls by RPC from CPRS
116 ;"Input: OUT-- Pass by reference. AN OUT PARAMETER.
117 ;" FILENUM -- The target file number that resulting IENs will be in
118 ;" STR -- This is a logic string for searching. See details above.
119 ;"Results: OUT is filled in. Format:
120 ;" OUT(0)=1 for success, or -1^Error Message
121 ;" OUT(IEN)=""
122 ;" OUT(IEN)=""
123 ;" OUT("COUNT")=Count of number of found records.
124 ;"Results: None
125 ;"
126 DO DOSRCH("OUT",.FILENUM,.STR) ;
127SRCHDN QUIT
128 ;
129 ;
130BKSRCH(FILENUM,STR) ;
131 ;"Purpose: this function is designed to be called via JOB, to setup separate job thread
132 ;" E.g. JOB BKSRCH^TMGTMGSRCH(FILENUM,STR) NEW MSGJOB SET MSGJOB=$ZJOB
133 ;" NOTE: When job, output MSG will be "#DONE#" (see below)
134 ;"Input: Filenum: This this is the target file of the search.
135 ;" STR -- This is the logic string for searching. Format as per SRCH() docs
136 ;"Output: Output will go into ^TMP("TMG","TMGSRCH",$J,"OUT")
137 ;" Messages will go into ^TMP("TMG","TMGSRCH",$J,"MSG")
138 ;" % Done will go into ^TMP("TMG","TMGSRCH",$J,"PCT")
139 ;"Results: none
140 NEW PGFN SET PGFN="DO BKPGFN^TMGSRCH(.TMGSTAT,.TMGPCT)"
141 NEW POUT SET POUT=$NAME(^TMP("TMG","TMGSRCH",$J,"OUT"))
142 KILL @POUT
143 DO DOSRCH(POUT,.FILENUM,.STR,PGFN) ;
144 DO BKPGFN("#DONE#",100)
145 QUIT ;"This should terminate thread (if called by JOB as above)
146 ;
147BKPGFN(MSG,PCT) ;
148 ;"Callable progress function code for background thread.
149 SET ^TMP("TMG","TMGSRCH",$J,"MSG")=$GET(MSG)
150 SET ^TMP("TMG","TMGSRCH",$J,"PCT")=$GET(PCT)
151 QUIT
152 ;
153 ;
154DOSRCH(PTMGOUT,FILENUM,STR,PGFN) ;
155 ;"Common entry endpoint for search entry tags. See docs in SRCH()
156 ;"Input: PTMGOUT -- Pass by NAME. The name of the output array
157 ;" FILENUM -- See SRCH()
158 ;" STR -- See SRCH()
159 ;" TMGPGFN -- OPTIONAL. Mumps code that will be called periodically
160 ;" to allow display of progress of slow searches.
161 ;" Code may depend on the following variables:
162 ;" TMGSTAT -- The most recent status text
163 ;" TMGPCT -- a very gross estimate of % done (0-100%)
164 ;"Results -- None.
165 NEW TMGARRAY,RESULT,CT
166 SET RESULT=$$PARSESTR(.FILENUM,STR,.TMGARRAY)
167 ;
168 ;"MERGE ^TMG("TMP","RPC","TMGRPCSR","TMGARRAY")=TMGARRAY ;"TEMP!!!
169 ;
170 IF +RESULT=-1 SET @PTMGOUT@(0)=RESULT GOTO DSRCHDN
171 SET CT=$$ARRYSRCH^TMGSRCH0(FILENUM,PTMGOUT,.TMGARRAY,.PGFN)
172 SET @PTMGOUT@("COUNT")=CT
173 SET @PTMGOUT@("FILENUM")=FILENUM
174 IF $GET(@PTMGOUT@(0))="" SET @PTMGOUT@(0)=1 ;"Success
175DSRCHDN QUIT
176 ;
177 ;
178PARSESTR(FILENUM,STR,ARRAY,FNUMPTR) ;
179 ;"Purpose: To take user input, validate it, and parse into an formatted array
180 ;"Input: FILENUM -- The file number that is the target of the search.
181 ;" STR: This is the user input string. Format as documented in SRCH() above.
182 ;" ARRAY -- PASS BY REFERENCE. An OUT PARAMETER. Format as follows.
183 ;" ARRAY(1,"FNUMPTR")= FNUM:FLDA[:FLDB[:FLDC...]] FNUM is filenumber that
184 ;" contain search field, and then fields used to point
185 ;" back to *TARGET* FILENUM for entire search
186 ;" ARRAY(1,"FLD")=Fieldnumber to search
187 ;" ARRAY(1,"COMP")=Comparator, will be "=", "'=", "'<", or "'>", "[", "{", "IN"
188 ;" ARRAY(1,"SRCH")=The value of to be used in search.
189 ;" ARRAY(1,"WP")=1 if field is a WP field
190 ;" ARRAY(2,...) The second search term.
191 ;" ARRAY(2,"LOGIC")=#^Combiner
192 ;" # means the set so far.
193 ;" Combiner will be "AND", "OR", or "NOT"
194 ;" ARRAY(3,...) The third search term (which is comprised of sub terms)
195 ;" ARRAY(3,1,... The first subterm (same format as higher level)
196 ;" ARRAY(3,2,... The second subterm (same format as higher level)
197 ;" ARRAY(n,...) The N'th search term.
198 ;" removed-> ARRAY("SETCOMP",i)= NumA^Combiner^NumB
199 ;" NumA and NumB refer to seach term number (e.g. 1, 2, ... n above)
200 ;" If NumA="#", then it means 'the resulting set of results so far'
201 ;" Combiner will be "AND", "OR", or "NOT"
202 ;" i is the index variable, and logic should be evaluated in numerical order
203 ;" FNUMPTR: Will be used when calling self reiteratively. Leave blank in first call.
204 ;" DON'T pass by reference. This is 'FileNum:FLD[:FLD[:FLD...]] specifier
205 ;"Results: 1 if OK, or -1^Message if error during processing.
206 ;
207 NEW SUBSTRA,SUBSTRB,POS
208 NEW RESULT SET RESULT=1 ;"default to success
209 NEW TERMNUM SET TERMNUM=0
210 SET FILENUM=+$GET(FILENUM)
211 IF FILENUM'>0 DO GOTO PSDN
212 . SET RESULT="-1^Target file number not provided."
213 SET FNUMPTR=$GET(FNUMPTR,FILENUM)
214 SET ARRAY("FILE")=FILENUM
215 NEW LOGICNUM SET LOGICNUM=0
216 NEW DONE SET DONE=0
217 FOR DO QUIT:(DONE=1)!(+RESULT=-1)
218 . NEW TEMPARRAY
219 . SET TERMNUM=TERMNUM+1
220 . ;"--- Get file number, if any
221 . SET STR=$$TRIM^XLFSTR(STR)
222 . IF +$PIECE(STR,"(",1)>0 DO QUIT:(+RESULT=-1)
223 . . SET FNUMPTR=$PIECE(STR,"(",1) ;"Convert 1234:.01:.02:(...) --> 1234:.01:.02:
224 . . IF $EXTRACT(FNUMPTR,$LENGTH(FNUMPTR))=":" SET FNUMPTR=$EXTRACT(FNUMPTR,1,$LENGTH(FNUMPTR)-1)
225 . . IF ($PIECE(FNUMPTR,":",2)="")&(+FNUMPTR'=FILENUM) DO QUIT:(+RESULT=-1)
226 . . . NEW SAVPTR SET SAVPTR=FNUMPTR
227 . . . SET FNUMPTR=$PIECE($$PATHTO^TMGSRCH1(+FNUMPTR,FILENUM),"^",1)
228 . . . IF FNUMPTR="" SET RESULT="-1^Unable to find path to file #"_FILENUM_" from "_SAVPTR
229 . . ELSE IF $$FNPTR^TMGSRCH1(FNUMPTR)'=FILENUM DO QUIT
230 . . . SET RESULT="-1^'"_FNUMPTR_"' points to file #"_$$FNPTR^TMGSRCH1(FNUMPTR)_", not file #"_FILENUM_" as expected"
231 . ;"Split STR --> SUBSTRA + SUBSTRB
232 . SET SUBSTRA=$$MATCHXTR^TMGSTUTL(STR,"(",,,"(")
233 . IF SUBSTRA="" SET DONE=1 QUIT
234 . SET POS=$FIND(STR,SUBSTRA) ;"Return pos of following character
235 . SET SUBSTRB=$EXTRACT(STR,POS+1,9999) ;"Should be " [LOGICTERM] [SearchTerm]..."
236 . ;"Process SUBSTRA, either directly if single term, or recursively if compound term.
237 . IF $$HNQTSUB^TMGSTUTL(SUBSTRA,"(") DO
238 . . SET RESULT=$$PARSESTR(FILENUM,SUBSTRA,.TEMPARRAY,FNUMPTR)
239 . . SET ARRAY(TERMNUM,"SUBTERMS")=1
240 . ELSE DO
241 . . SET RESULT=$$PARSE1(FILENUM,SUBSTRA,FNUMPTR,.TEMPARRAY)
242 . IF +RESULT=-1 QUIT
243 . SET SUBSTRA=""
244 . MERGE ARRAY(TERMNUM)=TEMPARRAY
245 . ;"Now get Logic term connecting this to next term (if any)
246 . SET SUBSTRB=$$TRIM^XLFSTR(SUBSTRB) ;"Remove opening (and closing) spaces
247 . NEW LOGICTERM SET LOGICTERM=""
248 . NEW P,CH
249 . NEW DNCOMB SET DNCOMB=0
250 . FOR P=1:1:$LENGTH(SUBSTRB) DO QUIT:DNCOMB!(+RESULT=-1)
251 . . SET CH=$$UP^XLFSTR($EXTRACT(SUBSTRB,P))
252 . . IF ("&|'!ANDORNOT"'[CH) SET DNCOMB=1 QUIT
253 . . SET LOGICTERM=LOGICTERM_CH
254 . SET STR=$EXTRACT(SUBSTRB,$LENGTH(LOGICTERM)+1,9999),SUBSTRB=""
255 . IF LOGICTERM="" QUIT
256 . SET LOGICTERM=$$FIXCOMB^TMGSRCH1(LOGICTERM,.RESULT) QUIT:(+RESULT=-1)
257 . NEW CURSET SET CURSET=$SELECT(TERMNUM=1:"1",1:"#")
258 . SET LOGICNUM=LOGICNUM+1
259 . ;"SET ARRAY("SETCOMP",LOGICNUM)=CURSET_"^"_LOGICTERM_"^"_(TERMNUM+1) ;"will check later that TERMNUM+1 is supplied
260 . SET ARRAY(TERMNUM+1,"LOGIC")="#^"_LOGICTERM
261PSDN QUIT RESULT
262 ;
263 ;
264PARSE1(FILENUM,STR,FNUMPTR,ARRAY) ;
265 ;"Purpose: Parse a simple search term (e.g. .01="SMITH,JOHN"). Also validate that field exists in file.
266 ;"Input: FILENUM -- The TARGET filenumber that the entire search is referencing.
267 ;" STR: This is part of the user input string to parse
268 ;" FNUMPTR: FNUM:FLDA[:FLDB[:FLDC...]] FNUM is filenumber that contain search field, and then
269 ;" fields used to point back to *TARGET* FILENUM for entire search
270 ;" ARRAY -- PASS BY REFERENCE. An OUT PARAMETER. Format as follows.
271 ;" ARRAY("FNUMPTR")=Filenumber that contains field)
272 ;" ARRAY("FLD")=Fieldnumber to search
273 ;" ARRAY("COMP")=Comparator, will be "=", "'=", "'<", or "'>", "[","IN", "{"
274 ;" ARRAY("SRCH")=The value of to be used in search.
275 ;" ARRAY("WP")=1 if field is a WP field
276 ;"NOTE: If field specifies a DATE, then the search value will be converted to FileMan format
277 ;"Results: 1 if OK, or -1^Message if error during processing.
278 ;"
279 NEW RESULT SET RESULT=1 ;"default to success
280 NEW SAV SET SAV=STR
281 SET STR=$$TRIM^XLFSTR($GET(STR))
282 SET ARRAY("FNUMPTR")=FNUMPTR
283 NEW FLD,FLDS SET FLDS=""
284 NEW TMGTFILE SET TMGTFILE=+FNUMPTR
285 FOR QUIT:("'<>=[:({"[$EXTRACT(STR,1))!(STR="") DO
286 . SET FLD=$$GETFLD^TMGSRCH1(.STR) ;
287 . NEW SAVFIL SET SAVFIL=TMGTFILE
288 . NEW ONEFLD SET ONEFLD=$$FLDNUM^TMGSRCH1(.TMGTFILE,.FLD)
289 . IF ONEFLD'>0 DO QUIT
290 . . SET RESULT="-1^Field ["_FLD_"] was not found in file ["_SAVFIL_"]"
291 . IF FLDS'="" SET FLDS=FLDS_":"
292 . SET FLDS=FLDS_ONEFLD
293 IF +RESULT=-1 GOTO PS1DN
294 SET ARRAY("FLD")=FLDS
295 IF $$ISWPFLD^TMGDBAPI(+FNUMPTR,+FLDS) SET ARRAY("WP")=1
296 NEW FLDTYPE SET FLDTYPE=$PIECE($GET(^DD(+FNUMPTR,+FLDS,0)),"^",2)
297 IF FLDTYPE["M" DO GOTO PS1DN
298 . SET RESULT="-1^Searches in fields that are MULTIPLES not supported"
299 SET STR=$$TRIM^XLFSTR(STR)
300 NEW COMP
301 IF $$UP^XLFSTR($EXTRACT(STR,1,3))="'IN" SET COMP="'IN"
302 ELSE IF $$UP^XLFSTR($EXTRACT(STR,1,2))="IN" SET COMP="IN"
303 ELSE DO
304 . SET COMP="" NEW P,CH
305 . FOR P=1:1:$LENGTH(STR) SET CH=$EXTRACT(STR,P) QUIT:("'!<>=[{"'[CH) SET COMP=COMP_CH
306 SET STR=$EXTRACT(STR,$LENGTH(COMP)+1,9999)
307 SET COMP=$$FIXCOMP^TMGSRCH1(COMP,.RESULT)
308 IF +RESULT=-1 GOTO PS1DN
309 SET ARRAY("COMP")=COMP
310 SET STR=$$TRIM^XLFSTR(STR) ;"Remove any spaces after comparator
311 NEW SRCH SET SRCH=$$TRIM^XLFSTR(STR,,"""") ;"Trim quotes, if any.
312 IF FLDTYPE["D" DO GOTO:(+RESULT=-1) PS1DN ;"standardized dates
313 . NEW ADATE SET ADATE=SRCH
314 . NEW TEMPRSLT SET TEMPRSLT=""
315 . FOR QUIT:(ADATE="")!(+RESULT=-1) DO
316 . . IF TEMPRSLT'="" SET TEMPRSLT=TEMPRSLT_".."
317 . . SET TEMPRSLT=TEMPRSLT_$$STDDATE^TMGSRCH1($PIECE(ADATE,"..",1),.RESULT)
318 . . IF +RESULT=-1 QUIT
319 . . SET ADATE=$PIECE(SRCH,"..",2)
320 . SET SRCH=TEMPRSLT
321 ELSE IF FLDTYPE["S" DO ;"Convert FM SET type into internal format
322 . NEW OUT,TMGMSG
323 . DO VAL^DIE(+FNUMPTR,"+1,",FLD,"E",SRCH,.OUT,,"TMGMSG")
324 . SET SRCH=$GET(OUT)
325 IF SRCH'="" SET ARRAY("SRCH")=SRCH
326 ELSE DO GOTO PS1DN
327 . SET RESULT="-1^Search value is invalid"
328 ;
329PS1DN IF +RESULT=-1 SET RESULT=RESULT_", found in ["_SAV_"]"
330 QUIT RESULT
331 ;
332 ;
333FMSRCH(TMGFILE,TMGCOMPEXPR,TMGOUT,TMGOPTION) ;
334 QUIT $$FMSRCH^TMGSRCH0(.TMGFILE,.TMGCOMPEXPR,.TMGOUT,.TMGOPTION)
335
Note: See TracBrowser for help on using the repository browser.