r4784: Auto commit for Debian build
[umlisp.git] / sql-classes.lisp
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: umlisp -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          sql-classes.lisp
6 ;;;; Purpose:       Routines for reading UMLS objects from SQL database
7 ;;;; Author:        Kevin M. Rosenberg
8 ;;;; Date Started:  Apr 2000
9 ;;;;
10 ;;;; $Id: sql-classes.lisp,v 1.58 2003/05/04 00:30:36 kevin Exp $
11 ;;;;
12 ;;;; This file, part of UMLisp, is
13 ;;;;    Copyright (c) 2000-2002 by Kevin M. Rosenberg, M.D.
14 ;;;;
15 ;;;; UMLisp users are granted the rights to distribute and use this software
16 ;;;; as governed by the terms of the GNU General Public License.
17 ;;;; *************************************************************************
18
19 (in-package :umlisp)
20 (declaim (optimize (compilation-speed 0) (debug 3)))
21
22
23 (defvar *current-srl* nil)
24 (defun current-srl ()
25   *current-srl*)
26 (defun current-srl! (srl)
27   (setq *current-srl* srl))
28
29 ;; only WHERE-VALUE and SRL are evaluated
30 (defmacro with-umlisp-query ((table fields srl where-name where-value
31                                     &key (lrl "KCUILRL") distinct single
32                                     order like)
33                              &body body)
34   (let ((value (gensym)))
35     (if single
36         `(let ((,value ,where-value))
37           (when ,value 
38             (let ((tuple (car (umlisp-query ,table ,fields ,srl ,where-name ,value
39                                             :lrl ,lrl :single ,single
40                                             :distinct ,distinct :order ,order
41                                             :like ,like))))
42               (when tuple
43                 (destructuring-bind ,fields tuple
44                   ,@body)))))
45         `(let ((,value ,where-value))
46           (when ,value 
47             (loop for tuple in
48                   (umlisp-query ,table ,fields ,srl ,where-name ,value
49                                 :lrl ,lrl :single ,single :distinct ,distinct
50                                 :order ,order :like ,like)
51                   collect (destructuring-bind ,fields tuple
52                             ,@body)))))))
53
54 (defmacro with-umlisp-query-eval ((table fields srl where-name where-value
55                                          &key (lrl "KCUILRL") distinct single
56                                          order like)
57                                   &body body)
58   (let ((value (gensym)))
59     (if single
60         `(let ((,value ,where-value))
61           (when ,value 
62             (let ((tuple (car (umlisp-query-eval ,table ,fields ,srl ,where-name ,value
63                                             :lrl ,lrl :single ,single
64                                             :distinct ,distinct :order ,order
65                                             :like ,like))))
66               (when tuple
67                 (destructuring-bind ,fields tuple
68                   ,@body)))))
69         `(let ((,value ,where-value))
70           (when ,value 
71             (loop for tuple in
72                   (umlisp-query-eval ,table ,fields ,srl ,where-name ,value
73                                      :lrl ,lrl :single ,single :distinct ,distinct
74                                      :order ,order :like ,like)
75                   collect (destructuring-bind ,fields tuple
76                             ,@body)))))))
77
78
79
80 (defmacro umlisp-query (table fields srl where-name where-value
81                      &key (lrl "KCUILRL") single distinct order like)
82   "Query the UMLisp database. Return a list of umlisp objects whose name
83 is OBJNAME from TABLE where WHERE-NAME field = WHERE-VALUE with FIELDS"
84   `(mutex-sql-query
85     (query-string-macro ,table ,fields ,srl ,where-name ,where-value 
86      :lrl ,lrl :single ,single :distinct ,distinct :order ,order :like ,like)))
87
88 (defun umlisp-query-eval (table fields srl where-name where-value
89                      &key (lrl "KCUILRL") single distinct order like)
90   "Query the UMLisp database. Return a list of umlisp objects whose name
91 is OBJNAME from TABLE where WHERE-NAME field = WHERE-VALUE with FIELDS"
92   (mutex-sql-query
93    (query-string-macro ,table ,fields ,srl ,where-name ,where-value 
94      :lrl ,lrl :single ,single :distinct ,distinct :order ,order :like ,like)))
95
96   
97 (defmacro query-string-macro (table fields &optional srl where-name where-value
98                         &key (lrl "KCUILRL") single distinct order like)
99   (let* ((%%fields (format nil "select ~A~{~:@(~A~)~^,~} from ~:@(~A~)"
100                            (if distinct "distinct " "") fields table))
101          (%%order (if order (format nil " order by ~{~:@(~A~) ~(~A~)~^,~}" order) ""))
102          (%%lrl (format nil " and ~:@(~A~)<=" lrl))
103          (%%where (when where-name
104                     (format nil " where ~:@(~A~)~A" where-name
105                           (if like " like " "=")))))
106     `(concatenate
107       'string
108       ,%%fields
109       ,@(when %%where (list %%where))
110       ,@(when %%where
111               `((if (numberp ,where-value)
112                     (write-to-string ,where-value)
113                     (format nil ,(if like "'%~A%'" "'~A'") ,where-value))))
114       (if ,srl (concatenate 'string ,%%lrl (write-to-string ,srl)) "")
115       ,@(when %%order (list %%order))
116       ,@(when single (list " limit 1")))))
117
118 (defun query-string (table fields &optional srl where-name where-value
119                      &key (lrl "KCUILRL") single distinct order like)
120   (concatenate
121    'string
122    (format nil "select ~A~{~:@(~A~)~^,~} from ~:@(~A~)" 
123            (if distinct "distinct " "") fields table)
124    (if where-name
125        (format nil
126                (if (stringp where-value)
127                    (if like
128                        " where ~A like '%~A%'"
129                        " where ~A='~A'")
130                    " where ~A=~A")
131                where-name  where-value)
132        "")
133    (if srl (format nil " and ~:@(~A~) <= ~D" lrl srl) "")
134    (if order (format nil " order by ~{~:@(~A~) ~(~A~)~^,~}" order) "")
135    (if single " limit 1" "")))
136
137 (defun find-ucon-cui (cui &key (srl *current-srl*))
138   "Find ucon for a cui"
139   (with-umlisp-query (mrcon (kpfstr kcuilrl) srl cui (parse-cui cui) :single t)
140     (make-instance 'ucon :cui (parse-cui cui)
141                    :pfstr kpfstr
142                    :lrl (ensure-integer kcuilrl))))
143
144 (defun find-ucon-cui-old (cui &key (srl *current-srl*))
145   "Find ucon for a cui"
146   (when (stringp cui) (setq cui (parse-cui cui)))
147   (when cui
148     (let ((ls (format nil "select KPFSTR,KCUILRL from MRCON where CUI=~d" cui)))
149       (when srl
150         (string-append ls (format nil " and KCUILRL <= ~d" srl)))
151       (string-append ls " limit 1")
152       (let ((tuple (car (mutex-sql-query ls))))
153         (destructuring-bind (kpfstr kcuilrl) tuple
154           (make-instance 'ucon :cui cui :pfstr kpfstr
155                          :lrl (ensure-integer kcuilrl)))))))
156
157 (defun find-ucon-cui-sans-pfstr (cui &key (srl *current-srl*))
158   "Find ucon for a cui"
159   (with-umlisp-query (mrcon (kcuilrl) srl cui (parse-cui cui) :single t)
160     (make-instance 'ucon :cui (parse-cui cui)
161                    :lrl (ensure-integer kcuilrl)
162                    :pfstr nil)))
163
164 (defun find-pfstr-cui (cui &key (srl *current-srl*))
165   "Find preferred string for a cui"
166   (with-umlisp-query (mrcon (kpfstr) srl cui (parse-cui cui) :single t)
167     kpfstr))
168
169 (defun find-ucon-lui (lui &key (srl *current-srl*))
170   "Find list of ucon for lui"
171   (with-umlisp-query (mrcon (cui kpfstr kcuilrl) srl lui (parse-lui lui) :distinct t)
172     (make-instance 'ucon :cui (ensure-integer cui)
173                    :pfstr kpfstr
174                    :lrl (ensure-integer kcuilrl))))
175
176 (defun find-ucon-sui (sui &key (srl *current-srl*))
177   "Find list of ucon for sui"
178   (with-umlisp-query (mrcon (cui kpfstr kcuilrl) srl sui (parse-sui sui) :distinct t)
179     (make-instance 'ucon :cui (ensure-integer cui)
180                    :pfstr kpfstr
181                    :lrl (ensure-integer kcuilrl))))
182
183 (defun find-ucon-cuisui (cui sui &key (srl *current-srl*))
184   "Find ucon for cui/sui"
185   (when (and cui sui)
186     (with-umlisp-query (mrcon (cui kpfstr kcuilrl) srl kcuisui 
187                                (make-cuisui (parse-cui cui) (parse-sui sui)))
188       (make-instance 'ucon :cui (ensure-integer cui)
189                      :pfstr kpfstr
190                      :lrl (ensure-integer kcuilrl)))))
191
192 (defun find-ucon-str (str &key (srl *current-srl*))
193   "Find ucon that are exact match for str"
194   (with-umlisp-query (mrcon (cui kpfstr kcuilrl) srl str str :distinct t)
195     (make-instance 'ucon :cui (ensure-integer cui) :pfstr kpfstr
196                    :lrl (ensure-integer kcuilrl))))
197
198 (defun find-ucon-all (&key (srl *current-srl*))
199   "Return list of all ucon's"
200   (with-sql-connection (db)
201     (clsql:map-query 
202      'list
203      #'(lambda (cui pfstr cuilrl)
204          (make-instance 'ucon :cui (ensure-integer cui)
205                         :pfstr pfstr
206                         :lrl (ensure-integer cuilrl)))
207      (query-string-macro mrcon (cui kpfstr kcuilrl) srl nil nil
208                    :order (cui asc) :distinct t)
209      :database db)))
210
211 (defun map-ucon-all (fn &key (srl *current-srl*))
212   "Map a function over all ucon's"
213   (with-sql-connection (db)
214     (clsql:map-query 
215      nil
216      #'(lambda (cui pfstr cuilrl)
217          (funcall fn
218                   (make-instance 'ucon :cui (ensure-integer cui)
219                                  :pfstr pfstr
220                                  :lrl (ensure-integer cuilrl))))
221      (query-string-macro mrcon (cui kpfstr kcuilrl) srl nil nil :order (cui asc) :distinct t)
222      :database db)))
223
224
225 (defun find-udef-cui (cui &key (srl *current-srl*))
226   "Return a list of udefs for cui"
227   (with-umlisp-query (mrdef (sab def) srl cui (parse-cui cui) :lrl "KSRL")
228     (make-instance 'udef :sab sab :def def)))
229
230 (defun find-usty-cui (cui &key (srl *current-srl*))
231   "Return a list of usty for cui"
232   (with-umlisp-query (mrsty (tui sty) srl cui (parse-cui cui) :lrl "KLRL")
233     (make-instance 'usty :tui (ensure-integer tui) :sty sty)))
234
235 (defun find-usty-word (word &key (srl *current-srl*))
236   "Return a list of usty that match word"
237   (with-umlisp-query (mrsty (tui sty) srl sty word :lrl klrl :like t :distinct t)
238     (make-instance 'usty :tui (ensure-integer tui) :sty sty)))
239
240 (defun find-urel-cui (cui &key (srl *current-srl*))
241   "Return a list of urel for cui"
242   (with-umlisp-query (mrrel (rel cui2 rela sab sl mg kpfstr2) srl cui1 (parse-cui cui) :lrl "KSRL")
243     (make-instance 'urel :cui1 (parse-cui cui) :rel rel :cui2 (ensure-integer cui2) :rela rela
244                    :sab sab :sl sl :mg mg :pfstr2 kpfstr2)))
245
246 (defun find-urel-cui2 (cui2 &key (srl *current-srl*))
247   "Return a list of urel for cui2"
248   (with-umlisp-query (mrrel (rel cui1 rela sab sl mg kpfstr2) srl cui2 (parse-cui cui2) :lrl "KSRL")
249     (make-instance 'urel :cui2 (parse-cui cui2) :rel rel :cui1 (ensure-integer cui1) :rela rela
250                    :sab sab :sl sl :mg mg :pfstr2 kpfstr2)))
251
252 (defun find-ucon-rel-cui2 (cui2 &key (srl *current-srl*))
253   (mapcar 
254    #'(lambda (cui) (find-ucon-cui cui :srl srl))
255    (remove-duplicates (mapcar #'cui1 (find-urel-cui2 cui2 :srl srl)))))
256
257 (defun find-ucoc-cui (cui &key (srl *current-srl*))
258   "Return a list of ucoc for cui"
259   (with-umlisp-query (mrcoc (cui2 soc cot cof coa kpfstr2) srl cui1 (parse-cui cui) 
260                              :lrl "KSRL" :order (cof asc))
261     (setq cui2 (ensure-integer cui2))
262     (when (zerop cui2) (setq cui2 nil))
263     (make-instance 'ucoc :cui1 (parse-cui cui) :cui2 (ensure-integer cui2) :soc soc :cot cot
264                    :cof (ensure-integer cof) :coa coa :pfstr2 kpfstr2)))
265
266 (defun find-ucoc-cui2 (cui2 &key (srl *current-srl*))
267   "Return a list of ucoc for cui2"
268   (with-umlisp-query (mrcoc (cui1 soc cot cof coa kpfstr2) srl cui2 (parse-cui cui2) 
269                              :lrl "KSRL" :order (cof asc))
270     (setq cui2 (ensure-integer cui2))
271     (when (zerop cui2) (setq cui2 nil))
272     (make-instance 'ucoc :cui1 (ensure-integer cui1) :cui2 (parse-cui cui2) :soc soc :cot cot
273                    :cof (ensure-integer cof) :coa coa :pfstr2 kpfstr2)))
274
275 (defun find-ucon-coc-cui2 (cui2 &key (srl *current-srl*))
276   "List of ucon with co-occurance cui2"
277   (mapcar 
278    #'(lambda (cui) (find-ucon-cui cui :srl srl))
279    (remove-duplicates (mapcar #'cui1 (find-ucoc-cui2 cui2 :srl srl)))))
280
281 (defun find-ulo-cui (cui &key (srl *current-srl*))
282   "Return a list of ulo for cui"
283   (with-umlisp-query (mrlo (isn fr un sui sna soui) srl cui (parse-cui cui) :lrl "KLRL")
284     (make-instance 'ulo :isn isn :fr (ensure-integer fr) :un un :sui (ensure-integer sui) :sna sna
285                    :soui soui)))
286
287 (defgeneric suistr (lo))
288 (defmethod suistr ((lo ulo))
289   "Return the string for a ulo object"
290   (find-string-sui (sui lo)))
291
292 (defun find-uatx-cui (cui &key (srl *current-srl*))
293   "Return a list of uatx for cui"
294   (with-umlisp-query (mratx (sab rel atx) srl cui (parse-cui cui) :lrl ksrl)
295     (make-instance 'uatx :sab sab :rel rel :atx atx)))
296
297
298 (defun find-uterm-cui (cui &key (srl *current-srl*))
299   "Return a list of uterm for cui"
300   (with-umlisp-query (mrcon (lui lat ts kluilrl) srl cui (parse-cui cui) :lrl kluilrl
301                              :distinct t)
302     (make-instance 'uterm :lui (ensure-integer lui) :cui (parse-cui cui)
303                    :lat lat :ts ts :lrl (ensure-integer kluilrl))))
304
305 (defun find-uterm-lui (lui &key (srl *current-srl*))
306   "Return a list of uterm for lui"
307   (with-umlisp-query (mrcon (cui lat ts kluilrl) srl lui (parse-lui lui) 
308                              :lrl kluilrl :distinct t)
309     (make-instance 'uterm :cui (ensure-integer cui) :lui (parse-lui lui)
310                    :lat lat :ts ts :lrl (ensure-integer kluilrl))))
311
312 (defun find-uterm-cuilui (cui lui &key (srl *current-srl*))
313   "Return single uterm for cui/lui"
314   (with-umlisp-query (mrcon (lat ts kluilrl) srl kcuilui
315                              (make-cuilui (parse-cui cui) (parse-lui lui))
316                              :lrl kluilrl :single t)
317     (make-instance 'uterm :cui cui :lui lui :lat lat :ts ts :lrl (ensure-integer kluilrl))))
318
319 (defun find-ustr-cuilui (cui lui &key (srl *current-srl*))
320   "Return a list of ustr for cui/lui"
321   (with-umlisp-query (mrcon (sui stt str lrl) srl kcuilui (make-cuilui cui lui) :lrl lrl)
322     (make-instance 'ustr :sui (ensure-integer sui) :cui cui :lui lui
323                    :cuisui (make-cuisui cui sui) :stt stt :str str
324                    :lrl (ensure-integer lrl))))
325
326 (defun find-ustr-cuisui (cui sui &key (srl *current-srl*))
327   "Return the single ustr for cuisui"
328   (with-umlisp-query (mrcon (lui stt str lrl) srl kcuisui (make-cuisui cui sui) :lrl lrl :single t)
329     (make-instance 'ustr :sui sui :cui cui :cuisui (make-cuisui cui sui)
330                    :lui (ensure-integer lui) :stt stt :str str :lrl (ensure-integer lrl))))
331
332 (defun find-ustr-sui (sui &key (srl *current-srl*))
333   "Return the list of ustr for sui"
334   (with-umlisp-query (mrcon (cui lui stt str lrl) srl sui (parse-sui sui) :lrl lrl)
335     (make-instance 'ustr :sui sui :cui cui :stt stt :str str
336                    :cuisui (make-cuisui (ensure-integer cui) (parse-sui sui))
337                    :lui (ensure-integer lui)
338                    :lrl (ensure-integer lrl))))
339       
340 (defun find-ustr-sab (sab &key (srl *current-srl*))
341   "Return the list of ustr for sab"
342   (with-umlisp-query (mrso (kcuisui) srl sab sab :lrl srl)
343     (let ((cuisui (ensure-integer kcuisui)))
344       (apply #'find-ustr-cuisui 
345              (append
346               (multiple-value-list (decompose-cuisui cuisui)) (list :srl srl))))))
347
348 (defun find-ustr-all (&key (srl *current-srl*))
349   "Return list of all ustr's"
350     (with-sql-connection (db)
351       (clsql:map-query 
352        'list
353        #'(lambda (cui lui sui stt lrl pfstr)
354            (setq cui (ensure-integer cui))
355            (setq lui (ensure-integer lui))
356            (setq sui (ensure-integer sui))      
357            (setq lrl (ensure-integer lrl))
358            (make-instance 'ustr :cui cui
359                           :lui lui
360                           :sui sui
361                           :cuisui (make-cuisui cui sui)
362                           :stt stt
363                           :lrl lrl
364                           :str pfstr))
365        (query-string-macro mrcon (cui lui sui stt lrl kpfstr) srl nil nil :lrl lrl :distinct t
366                      :order (sui asc))
367        :database db)))
368
369 (defun find-string-sui (sui &key (srl *current-srl*))
370   "Return the string associated with sui"
371   (with-umlisp-query (mrcon (str) srl sui sui :lrl lrl :single t)
372     str))
373
374 (defun find-uso-cuisui (cui sui &key (srl *current-srl*))
375   (with-umlisp-query (mrso (sab code srl tty) srl kcuisui (make-cuisui cui sui) :lrl srl)
376       (make-instance 'uso :sab sab :code code :srl srl :tty tty)))
377
378 (defun find-ucxt-cuisui (cui sui &key (srl *current-srl*))
379   (with-umlisp-query (mrcxt (sab code cxn cxl rnk cxs cui2 hcd rela xc) srl kcuisui
380                              (make-cuisui cui sui) :lrl ksrl)
381     (make-instance 'ucxt :sab sab :code code
382                    :cxn (ensure-integer cxn)
383                    :cxl cxl :cxs cxs :hcd hcd :rela rela :xc xc
384                    :rnk (ensure-integer rnk)
385                    :cui2 (ensure-integer cui2))))
386
387 (defun find-usat-ui (cui &optional (lui nil) (sui nil) &key (srl *current-srl*))
388   (let ((ls (format nil "select CODE,ATN,SAB,ATV from MRSAT where ")))
389     (cond
390       (sui (string-append ls (format nil "KCUISUI=~d" (make-cuisui cui sui))))
391       (lui (string-append ls (format nil "KCUILUI=~d and sui=0" (make-cuilui cui lui))))
392       (t (string-append ls (format nil "cui=~d and lui=0 and sui=0" cui))))
393     (when srl
394       (string-append ls (format nil " and KSRL <= ~d" srl)))
395     (loop for tuple in (mutex-sql-query ls) collect 
396           (destructuring-bind (code atn sab atv) tuple
397             (make-instance 'usat :code code :atn atn :sab sab :atv atv)))))
398
399 (defun find-usty-tui (tui)
400   "Find usty for tui"
401   (with-umlisp-query (mrsty (sty) nil tui (parse-tui tui) :single t)
402     (make-instance 'usty :tui (parse-tui tui) :sty sty)))
403
404 (defun find-usty-sty (sty)
405   "Find usty for a sty"
406   (with-umlisp-query (mrsty (tui) nil sty sty :single t)
407     (make-instance 'usty :tui (ensure-integer tui) :sty sty)))
408
409 (defun find-usty-all ()
410   "Return list of usty's for all semantic types"
411   (with-umlisp-query (mrsty (tui) nil nil nil :distinct t)
412     (find-usty-tui tui)))
413
414 (defun find-usab-all ()
415   "Find usab for a key"
416   (with-umlisp-query (mrsab (vcui rcui vsab rsab son sf sver mstart mend imeta rmeta slc scc srl tfr cfr cxty ttyl atnl lat cenc curver sabin) nil nil nil)
417     (make-instance 'usab :vcui (ensure-integer vcui) 
418                    :rcui (ensure-integer rcui)
419                    :vsab vsab :rsab rsab :son son :sf sf :sver sver :mstart mstart
420                    :mend mend :imeta imeta :rmeta rmeta :slc slc :scc scc
421                    :srl (ensure-integer srl) 
422                    :tfr (ensure-integer tfr) :cfr (ensure-integer cfr)
423                    :cxty cxty :ttyl ttyl :atnl atnl :lat lat :cenc cenc
424                    :curver curver :sabin sabin)))
425
426 (defun find-usab-by-key (key-name key)
427   "Find usab for a key"
428   (with-umlisp-query-eval ('mrsab '(vcui rcui vsab rsab son sf sver mstart mend imeta rmeta slc scc srl tfr cfr cxty ttyl atnl lat cenc curver sabin) nil key-name key :single t)
429     (make-instance 'usab :vcui (ensure-integer vcui) 
430                    :rcui (ensure-integer rcui)
431                    :vsab vsab :rsab rsab :son son :sf sf :sver sver :mstart mstart
432                    :mend mend :imeta imeta :rmeta rmeta :slc slc :scc scc
433                    :srl (ensure-integer srl) 
434                    :tfr (ensure-integer tfr) :cfr (ensure-integer cfr)
435                    :cxty cxty :ttyl ttyl :atnl atnl :lat lat :cenc cenc
436                    :curver curver :sabin sabin)))
437
438 (defun find-usab-rsab (rsab)
439   "Find usab for rsab"
440   (find-usab-by-key 'rsab rsab))
441
442 (defun find-usab-vsab (vsab)
443   "Find usab for vsab"
444   (find-usab-by-key 'vsab vsab))
445
446 (defun find-cui-max ()
447   (ensure-integer (caar (mutex-sql-query "select max(CUI) from MRCON"))))
448
449 ;;;; Cross table find functions
450
451 (defun find-ucon-tui (tui &key (srl *current-srl*))
452   "Find list of ucon for tui"
453   (with-umlisp-query (mrsty (cui) srl tui (parse-tui tui) :lrl klrl
454                              :order (cui asc))
455     (find-ucon-cui (ensure-integer cui) :srl srl)))
456   
457 (defun find-ucon-word (word &key (srl *current-srl*) (like nil))
458   "Return list of ucons that match word. Optionally, use SQL's LIKE syntax"
459   (with-umlisp-query-eval ('mrxw_eng '(cui) srl 'wd word :like like :distinct t
460                                      :lrl klrl :order '(cui asc))
461     (find-ucon-cui cui :srl srl)))
462
463 (defun find-ucon-normalized-word (word &key (srl *current-srl*) (like nil))
464   "Return list of ucons that match word, optionally use SQL's LIKE syntax"
465   (with-umlisp-query-eval ('mrxnw_eng '(cui) srl 'nwd word :like like :distinct t
466                                       :lrl klrl :order '(cui asc))
467     (find-ucon-cui cui :srl srl)))
468
469 (defun find-ustr-word (word &key (srl *current-srl*))
470   "Return list of ustrs that match word"
471   (with-umlisp-query (mrxw_eng (cui sui) srl wd word
472                                 :lrl klrl
473                                 :order (cui asc sui asc))
474     (find-ustr-cuisui (ensure-integer cui) (ensure-integer sui) :srl srl)))
475
476 (defun find-ustr-normalized-word (word &key (srl *current-srl*))
477   "Return list of ustrs that match word"
478   (with-umlisp-query (mrxnw_eng (cui sui) srl nwd word :lrl klrl
479                                  :order (cui asc sui asc))
480     (find-ustr-cuisui (ensure-integer cui) (ensure-integer sui) :srl srl)))
481
482 ;; Special tables
483
484 (defun find-usrl-all ()
485   (with-umlisp-query (usrl (sab srl) nil nil nil :order (sab asc))
486     (make-instance 'usrl :sab sab :srl (ensure-integer srl))))
487
488 ;;; Multiword lookup and score functions
489
490 (defun find-ucon-multiword (str &key (srl *current-srl*))
491   "Return sorted list of ucon's that match a multiword string"
492   (let* ((words (delimited-string-to-list str #\space))
493          (ucons '()))
494     (dolist (word words)
495       (setq ucons (append ucons (find-ucon-word word :srl srl))))
496     (sort-score-ucon-str str (delete-duplicates ucons :test #'eql :key #'cui))))
497
498 (defun find-ustr-multiword (str &key (srl *current-srl*))
499   "Return sorted list of ustr's that match a multiword string"
500   (let* ((words (delimited-string-to-list str #\space))
501          (ustrs '()))
502     (dolist (word words)
503       (setq ustrs (append ustrs (find-ustr-word word :srl srl))))
504     (sort-score-ustr-str str (delete-duplicates ustrs :test #'eql :key #'cui))))
505         
506 (defun sort-score-ucon-str (str ucons)
507   "Return list of sorted and scored ucons. Score by match of str to ucon-pfstr"
508   (sort-score-umlsclass-str ucons str #'pfstr))
509
510 (defun sort-score-ustr-str (str ustrs)
511   "Return list of sorted and scored ucons. Score by match of str to ucon-pfstr"
512   (sort-score-umlsclass-str ustrs str #'str))
513
514 (defun sort-score-umlsclass-str (objs str lookup-func)
515   "Sort a list of objects based on scoring to a string"
516   (let ((scored '()))
517     (dolist (obj objs)
518       (push 
519        (list obj 
520              (score-multiword-match str (funcall lookup-func obj))) 
521        scored))
522     (mapcar #'car (sort scored #'> :key #'cadr))))
523
524 (defun score-multiword-match (s1 s2)
525   "Score a match between two strings with s1 being reference string"
526   (let* ((word-list-1 (delimited-string-to-list s1 #\space))
527          (word-list-2 (delimited-string-to-list s2 #\space))
528          (n1 (length word-list-1))
529          (n2 (length word-list-2))
530          (unmatched n1)
531          (score 0)
532          (nlong 0)
533          (nshort 0)
534          short-list long-list)
535     (declare (fixnum n1 n2 nshort nlong score unmatched))
536     (if (> n1 n2)
537         (progn
538           (setq nlong n1)
539           (setq nshort n2)
540           (setq long-list word-list-1)
541           (setq short-list word-list-2))
542       (progn
543         (setq nlong n2)
544         (setq nshort n1)
545         (setq long-list word-list-2)
546         (setq short-list word-list-1)))
547     (decf score (- nlong nshort)) ;; reduce score for extra words
548     (dotimes (iword nshort)
549       (declare (fixnum iword))
550       (kmrcl:aif (position (nth iword short-list) long-list :test #'string-equal)
551            (progn
552              (incf score (- 10 (abs (- kmrcl::it iword))))
553              (decf unmatched))))
554     (decf score (* 2 unmatched))
555     score))
556
557
558 ;;; LEX SQL functions
559
560 (defun find-lexterm-eui (eui)
561   (with-umlisp-query (lrwd (wrd) nil eui eui :single t)
562     (make-instance 'lexterm :eui eui :wrd wrd)))
563
564 (defun find-lexterm-word (wrd)
565   (with-umlisp-query (lrwd (eui) nil wrd wrd)
566     (make-instance 'lexterm :eui (ensure-integer eui)
567                    :wrd (copy-seq wrd))))
568
569 ;; LEX SQL Read functions
570
571 (defun find-labr-eui (eui)
572   (with-umlisp-query (lrabr (bas abr eui2 bas2) nil eui eui) 
573     (make-instance 'labr :eui eui :bas bas :abr abr :bas2 bas2
574                    :eui2 (ensure-integer eui2))))
575
576 (defun find-labr-bas (bas)
577   (with-umlisp-query (labr (eui abr eui2 bas2) nil bas bas)
578     (make-instance 'labr :eui (ensure-integer eui) :abr abr :bas2 bas2
579                    :bas (copy-seq bas) :eui2 (ensure-integer eui2))))
580
581 (defun find-lagr-eui (eui)
582   (with-umlisp-query (lragr (str sca agr cit bas) nil eui eui)
583     (make-instance 'lagr :eui eui :str str :sca sca :agr agr
584                    :cit cit :bas bas)))
585
586 (defun find-lcmp-eui (eui)
587   (with-umlisp-query (lrcmp (bas sca com) nil eui eui)
588     (make-instance 'lcmp :eui eui :bas bas :sca sca :com com)))
589
590 (defun find-lmod-eui (eui)
591   (with-umlisp-query (lrmod (bas sca psn_mod fea) nil eui eui)
592     (make-instance 'lmod :eui eui :bas bas :sca sca :psnmod psn_mod :fea fea)))
593
594 (defun find-lnom-eui (eui)
595   (with-umlisp-query (lrnom (bas sca eui2 bas2 sca2) nil eui eui)
596     (make-instance 'lnom :eui eui :bas bas :sca sca :bas2 bas2 :sca2 sca2
597                    :eui2 (ensure-integer eui2))))
598
599 (defun find-lprn-eui (eui)
600   (with-umlisp-query (lrprn (bas num gnd cas pos qnt fea) nil eui eui)
601     (make-instance 'lprn :eui eui :bas bas :num num :gnd gnd
602                    :cas cas :pos pos :qnt qnt :fea fea)))
603
604 (defun find-lprp-eui (eui)
605   (with-umlisp-query (lrprp (bas str sca fea) nil eui eui)
606     (make-instance 'lprp :eui eui :bas bas :str str :sca sca :fea fea)))
607
608 (defun find-lspl-eui (eui)
609   (with-umlisp-query (lrspl (spv bas) nil eui eui)
610     (make-instance 'lspl :eui eui :spv spv :bas bas)))
611
612 (defun find-ltrm-eui (eui)
613   (with-umlisp-query (lrtrm (bas gen) nil eui eui) 
614     (make-instance 'ltrm :eui eui :bas bas :gen gen)))
615
616 (defun find-ltyp-eui (eui)
617   (with-umlisp-query (lrtyp (bas sca typ) nil eui eui)
618     (make-instance 'ltyp :eui eui :bas bas :sca sca :typ typ)))
619
620 (defun find-lwd-wrd (wrd)
621   (make-instance 'lwd :wrd
622                  :euilist (with-umlisp-query (lrwd (eui) nil wrd wrd)
623                             (ensure-integer eui))))
624
625 ;;; Semantic Network SQL access functions
626
627 (defun find-sdef-ui (ui)
628   (with-umlisp-query (srdef (rt sty_rl stn_rtn def ex un rh abr rin)
629                             nil ui ui :single t)
630     (make-instance 'sdef :rt rt :ui ui :styrl sty_rl :stnrtn stn_rtn
631                    :def def :ex ex :un un :rh rh :abr abr :rin rin)))
632
633 (defun find-sstre1-ui (ui)
634   (with-umlisp-query (srstre1 (ui2 ui3) nil ui ui)
635     (make-instance 'sstre1 :ui ui :ui2 (ensure-integer ui2)
636                    :ui3 (ensure-integer ui3))))
637
638 (defun find-sstre1-ui2 (ui2)
639   (with-umlisp-query (srstre1 (ui ui3) nil ui2 ui2)
640     (make-instance 'sstre1 :ui (ensure-integer ui) :ui2 ui2
641                    :ui3 (ensure-integer ui3))))
642
643 (defun find-sstr-rl (rl)
644   (with-umlisp-query (srstre (sty_rl sty_rl2 ls) nil rl rl)
645     (make-instance 'sstr :rl rl :styrl sty_rl :styrl2 sty_rl2 :ls ls)))
646
647 (defun find-sstre2-sty (sty)
648   (with-umlisp-query (srstre2 (rl sty2) nil sty sty)
649     (make-instance 'sstre2 :sty (copy-seq sty) :rl rl :sty2 sty2)))
650
651 (defun find-sstr-styrl (styrl)
652   (with-umlisp-query (srstr (rl sty_rl2 ls) nil styrl styrl)
653     (make-instance 'sstr :styrl styrl :rl rl :styrl2 sty_rl2 :ls ls)))