001package org.hl7.fhir.convertors.misc;
002
003import java.io.File;
004import java.io.FileInputStream;
005import java.io.FileNotFoundException;
006import java.io.IOException;
007import java.sql.Connection;
008import java.sql.DriverManager;
009import java.sql.PreparedStatement;
010import java.sql.SQLException;
011import java.sql.Statement;
012import java.util.HashMap;
013import java.util.HashSet;
014import java.util.Map;
015import java.util.Set;
016
017import org.hl7.fhir.exceptions.FHIRException;
018import org.hl7.fhir.utilities.CSVReader;
019import org.hl7.fhir.utilities.Utilities;
020import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
021
022@SuppressWarnings("checkstyle:systemout")
023public class OMOPImporter {
024
025  public class Tracker {
026    private int blip;
027    private long start;
028    private int counter = 0;
029    boolean processed = false;
030
031    public Tracker(String name, int estimate) {
032      this.start = System.currentTimeMillis();
033      this.blip = estimate < 100 ? 1 : estimate / 80;
034      System.out.print(name);
035    }
036
037    public void skip() {
038      System.out.println(" ... skipped");
039    }
040    
041    public void scan() {
042      System.out.println("");
043      System.out.print(" Scan :");
044      counter = 0;
045    }
046
047    public void process() {
048      System.out.println("");
049      System.out.print(" Build:");
050      counter = 0;
051      processed = true;
052    }
053
054    public void step() {
055      counter++;
056      if (counter % blip == 0) {
057        System.out.print(".");
058      }
059    }
060
061    public void done() {
062      if (counter > 0) {
063        System.out.println("");        
064      }
065      if (processed) {
066        long elapsed = System.currentTimeMillis()-start; 
067        if (elapsed > 3000) {
068          System.out.println(" Finished: "+counter+" rows, "+Utilities.describeDuration(elapsed)+" ("+(counter/(elapsed/1000))+" rows/msec)");
069        } else {
070          System.out.println(" Finished: "+counter+" rows, "+Utilities.describeDuration(elapsed));
071        }
072      } else {
073        System.out.println(" Finished: "+counter+" rows");        
074      }
075    }
076
077
078    public void error(String e) {
079      System.out.println("error: "+e);
080      System.out.println("row: "+counter);        
081      throw new Error(e);
082    }
083
084  }
085
086  private Connection con;
087  private Map<String, String> relationships = new HashMap<>();
088  private Map<String, String> vocabularies = new HashMap<>();
089  private Map<String, String> domains = new HashMap<>();
090  private Map<String, String> classes = new HashMap<>();
091  private Set<String> conceptFilter = null;
092
093  public static void main(String[] args) throws Exception {
094    new OMOPImporter().process(args[0], args[1], args.length > 2 ? args[2] : null); 
095    // "/Users/grahamegrieve/Downloads/vocabulary_download_v5_{97cc5432-0dc9-4f14-9da2-d0624129d2f7}_1688068174909");
096    // /Users/grahamegrieve/temp/omop/omop.db
097  }
098
099  private void process(String folder, String dest, String filter) throws ClassNotFoundException, SQLException, FHIRException, FileNotFoundException, IOException {
100    connect(dest);
101    
102    if (filter != null) {
103      processFilter(filter);
104    }
105
106    processRelationships(folder, true);
107    processVocabularies(folder, true);
108    processDomains(folder, true);
109    processConceptClasses(folder, true);
110    processConcepts(folder, true);
111    processConceptSynonyms(folder, true);
112    processConceptRelationships(folder, true);
113    // disabled - don't consume space that isn't required
114    processDrugStrength(folder, false);
115    processConceptAncestors(folder, false);
116  }
117
118
119  private void processFilter(String filter) throws FHIRException, IOException {
120    conceptFilter = new HashSet<String>();
121    CSVReader csv = new CSVReader(new FileInputStream(filter));
122    csv.readHeaders();
123    while (csv.line()) {
124      conceptFilter.add(csv.cell("concept_id"));
125    }
126    
127  }
128
129  private void connect(String dest) throws SQLException, ClassNotFoundException, IOException {
130    //    Class.forName("com.mysql.jdbc.Driver");  
131    //    con = DriverManager.getConnection("jdbc:mysql://localhost:3306/omop?useSSL=false","root",{pwd}); 
132    ManagedFileAccess.file(dest).delete();
133    con = DriverManager.getConnection("jdbc:sqlite:"+dest); 
134  }
135  private void processRelationships(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
136    Tracker t = new Tracker("Relationships", 700);
137    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "RELATIONSHIP.csv")));
138    csv.setDelimiter('\t');
139    csv.readHeaders();
140    csv.setDoingQuotes(false);
141    int lid = 0;
142    int lname = 0;
143
144    t.scan();
145    while (csv.line()) {
146      relationships.put(csv.cell("relationship_id"), csv.cell("relationship_concept_id"));
147
148      lid = max(lid, csv.cell("relationship_id"));
149      lname = max(lname, csv.cell("relationship_name"));
150      t.step();
151    }
152
153    csv.close();   
154    if (process) {
155      t.process();
156      Statement stmt = con.createStatement();
157      stmt.execute("CREATE TABLE Relationships (\r\n"+
158          "`relationship_concept_id` bigint NOT NULL,\r\n"+
159          "`relationship_id` varchar("+lid+") DEFAULT NULL,\r\n"+
160          "`relationship_name` varchar("+lname+") DEFAULT NULL,\r\n"+
161          "`is_hierarchical` int DEFAULT NULL,\r\n"+
162          "`defines_ancestry` int DEFAULT NULL,\r\n"+
163          "`reverse_relationship_id` varchar(45) DEFAULT NULL,\r\n"+
164          "PRIMARY KEY (`relationship_concept_id`))\r\n");
165
166      stmt.execute("Create Index `RelationshipsId` on Relationships  (`relationship_id`)");
167      stmt.execute("Create Index`RelationshipsReverse` on Relationships (`reverse_relationship_id`)");
168
169      csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "RELATIONSHIP.csv")));
170      csv.setDelimiter('\t');
171      csv.readHeaders();
172      csv.setDoingQuotes(false);
173
174      while (csv.line()) {
175        relationships.put(csv.cell("relationship_id"), csv.cell("relationship_concept_id"));
176        if (process) {
177          String sql = "INSERT INTO `Relationships` (`relationship_concept_id`, `relationship_id`, `relationship_name`, `is_hierarchical`, `defines_ancestry`, `reverse_relationship_id`) VALUES ("+
178              sw(csv.cell("relationship_concept_id"))+", "+
179              sw(csv.cell("relationship_id"))+", "+
180              sw(csv.cell("relationship_name"))+", "+
181              sw(csv.cell("is_hierarchical"))+", "+
182              sw(csv.cell("defines_ancestry"))+", "+
183              sw(csv.cell("reverse_relationship_id"))+")";
184          try {
185            stmt.executeUpdate(sql);
186          } catch (Exception e) {
187            t.error(e.getMessage());
188          }
189        }
190        t.step();
191      }
192      csv.close();    
193    }
194    t.done();
195  }
196
197  private int max(int lid, String cell) {
198    int i = cell == null? 0 : cell.length();
199    return i > lid ? i : lid;
200  }
201
202  private void processVocabularies(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
203    Tracker t = new Tracker("Vocabularies", 60);
204    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "VOCABULARY.csv")));
205    csv.setDelimiter('\t');
206    csv.readHeaders();
207    csv.setDoingQuotes(false);
208    int lid = 0;
209    int lname = 0;
210    int lref = 0;
211    int lver = 0;
212    t.scan();
213    while (csv.line()) {
214      vocabularies.put(csv.cell("vocabulary_id"), csv.cell("vocabulary_concept_id"));
215
216      lid = max(lid, csv.cell("vocabulary_id"));
217      lname = max(lname, csv.cell("vocabulary_name"));
218      lref = max(lref, csv.cell("vocabulary_reference"));
219      lver = max(lver, csv.cell("vocabulary_version"));
220      t.step();
221    }
222    csv.close(); 
223
224    if (process) {
225      t.process();
226      Statement stmt = con.createStatement();
227
228      stmt.execute("CREATE TABLE `Vocabularies` (\r\n"+
229          "  `vocabulary_concept_id` bigint NOT NULL,\r\n"+
230          "  `vocabulary_id` varchar("+lid+") DEFAULT NULL,\r\n"+
231          "  `vocabulary_name` varchar("+lname+") DEFAULT NULL,\r\n"+
232          "  `vocabulary_reference` varchar("+lref+") DEFAULT NULL,\r\n"+
233          "  `vocabulary_version` varchar("+lver+") DEFAULT NULL,\r\n"+
234          "  PRIMARY KEY (`vocabulary_concept_id`)\r\n"+
235          ") \r\n"+
236          "\r\n");
237      stmt.execute("CREATE INDEX `VocabulariesId` on Vocabularies (`vocabulary_id`)");
238
239      csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "VOCABULARY.csv")));
240      csv.setDelimiter('\t');
241      csv.readHeaders();
242      csv.setDoingQuotes(false);
243      while (csv.line()) {
244        String sql = "INSERT INTO `Vocabularies` (`vocabulary_concept_id`, `vocabulary_id`, `vocabulary_name`, `vocabulary_reference`, `vocabulary_version`) VALUES ("+
245            sw(csv.cell("vocabulary_concept_id"))+", "+
246            sw(csv.cell("vocabulary_id"))+", "+
247            sw(csv.cell("vocabulary_name"))+", "+
248            sw(csv.cell("vocabulary_reference"))+", "+
249            sw(csv.cell("vocabulary_version"))+")";
250        try {
251          stmt.executeUpdate(sql);
252        } catch (Exception e) {
253          t.error(e.getMessage());
254        }
255        t.step();
256      }
257      csv.close(); 
258    }
259    t.done();
260  }
261
262
263  private void processDomains(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
264    Tracker t = new Tracker("Domains", 50);
265
266    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "DOMAIN.csv")));
267    csv.setDelimiter('\t');
268    csv.readHeaders();
269    csv.setDoingQuotes(false);
270    int lid = 0;
271    int lname = 0;
272    t.scan();
273    while (csv.line()) {
274
275      domains.put(csv.cell("domain_id"), csv.cell("domain_concept_id"));
276
277      lid = max(lid, csv.cell("domain_id"));
278      lname = max(lname, csv.cell("domain_name"));
279      t.step();
280    }
281    csv.close();
282
283    if (process) {
284      t.process();
285      Statement stmt = con.createStatement();
286
287      stmt.execute("CREATE TABLE `Domains` (\r\n"+
288          "  `domain_concept_id` bigint NOT NULL,\r\n"+
289          "  `domain_id` varchar("+lid+") DEFAULT NULL,\r\n"+
290          "  `domain_name` varchar("+lname+") DEFAULT NULL,\r\n"+
291          "  PRIMARY KEY (`domain_concept_id`)\r\n"+
292          ") \r\n"+
293          "\r\n");
294
295      stmt.execute("CREATE INDEX `DomainId` on Domains (`domain_id`)");
296
297      csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "DOMAIN.csv")));
298      csv.setDelimiter('\t');
299      csv.readHeaders();
300      csv.setDoingQuotes(false);
301      while (csv.line()) {
302        String sql = "INSERT INTO `Domains` (`domain_concept_id`, `domain_id`, `domain_name`) VALUES ("+
303            sw(csv.cell("domain_concept_id"))+", "+
304            sw(csv.cell("domain_id"))+", "+
305            sw(csv.cell("domain_name"))+")";
306        try {
307          stmt.executeUpdate(sql);
308        } catch (Exception e) {
309          t.error(e.getMessage());
310        }
311        t.step();
312      }
313      csv.close();
314    }
315    t.done();
316  }
317
318  private void processConceptClasses(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
319    Tracker t = new Tracker("ConceptClasses", 400);
320
321    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT_CLASS.csv")));
322    csv.setDelimiter('\t');
323    csv.readHeaders();
324    csv.setDoingQuotes(false);
325    int lid = 0;
326    int lname = 0;
327    t.scan();
328    while (csv.line()) {
329      classes.put(csv.cell("concept_class_id"), csv.cell("concept_class_concept_id"));
330
331      lid = max(lid, csv.cell("concept_class_id"));
332      lname = max(lname, csv.cell("concept_class_name"));
333      t.step();
334    }
335    csv.close(); 
336
337    if (process) {
338      t.process();
339      Statement stmt = con.createStatement();
340      stmt.execute("CREATE TABLE `ConceptClasses` (\r\n"+
341          "  `concept_class_concept_id` bigint NOT NULL,\r\n"+
342          "  `concept_class_id` varchar("+lid+") DEFAULT NULL,\r\n"+
343          "  `concept_class_name` varchar("+lname+") DEFAULT NULL,\r\n"+
344          "  PRIMARY KEY (`concept_class_concept_id`)\r\n"+
345          ") \r\n"+
346          "\r\n");
347      csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT_CLASS.csv")));
348      csv.setDelimiter('\t');
349      csv.readHeaders();
350      csv.setDoingQuotes(false);
351
352      while (csv.line()) {
353        String sql = "INSERT INTO `ConceptClasses` (`concept_class_concept_id`, `concept_class_id`, `concept_class_name`) VALUES ("+
354            sw(csv.cell("concept_class_concept_id"))+", "+
355            sw(csv.cell("concept_class_id"))+", "+
356            sw(csv.cell("concept_class_name"))+")";
357        try {
358          stmt.executeUpdate(sql);
359        } catch (Exception e) {
360          t.error(e.getMessage());
361        }
362        t.step();
363      }
364      csv.close();
365    }
366    t.done();
367
368  }
369
370
371  private void processDrugStrength(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
372    Tracker t = new Tracker("DrugStrengths", 3000000);
373    if (!process) {
374      t.skip();
375      return;
376    }
377
378    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "DRUG_STRENGTH.csv")));
379    csv.setDelimiter('\t');
380    csv.readHeaders();
381    csv.setDoingQuotes(false);
382    int lreason = 0;
383    int lamount1 = 0;
384    int lnum1 = 0;
385    int lden1 = 0;
386    int lamount2 = 0;
387    int lnum2 = 0;
388    int lden2 = 0;
389    t.scan();
390    while (csv.line()) {
391      lreason = max(lreason, csv.cell("invalid_reason"));
392      lamount1 = dmax1(lamount1, csv.cell("amount_value"));
393      lamount2 = dmax2(lamount2, csv.cell("amount_value"));
394      lnum1 = dmax1(lnum1, csv.cell("numerator_value"));
395      lnum2 = dmax2(lnum2, csv.cell("numerator_value"));
396      lden1 = dmax1(lden1, csv.cell("denominator_value"));
397      lden2 = dmax2(lden2, csv.cell("denominator_value"));
398      t.step();
399    }
400    csv.close();
401    t.process();
402
403    Statement stmt = con.createStatement();
404    stmt.execute("CREATE TABLE `DrugStrengths` (\r\n"+
405        "  `drug_concept_id` bigint NOT NULL,\r\n"+
406        "  `ingredient_concept_id` bigint NOT NULL,\r\n"+
407        "  `amount_value` decimal("+lamount1+","+lamount2+") DEFAULT NULL,\r\n"+
408        "  `amount_unit_concept_id` bigint DEFAULT NULL,\r\n"+
409        "  `numerator_value` decimal("+lnum1+","+lnum2+") DEFAULT NULL,\r\n"+
410        "  `numerator_unit_concept_id` bigint DEFAULT NULL,\r\n"+
411        "  `denominator_value` decimal("+lden1+","+lden2+") DEFAULT NULL,\r\n"+
412        "  `denominator_unit_concept_id` bigint DEFAULT NULL,\r\n"+
413        "  `box_size` int DEFAULT NULL,\r\n"+
414        "  `valid_start_date` date DEFAULT NULL,\r\n"+
415        "  `valid_end_date` date DEFAULT NULL,\r\n"+
416        "  `invalid_reason` varchar("+lreason+") DEFAULT NULL,\r\n"+
417        "  PRIMARY KEY (`drug_concept_id`,`ingredient_concept_id`)\r\n"+
418        ") \r\n"+
419        "\r\n");
420    csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "DRUG_STRENGTH.csv")));
421    csv.setDelimiter('\t');
422    csv.readHeaders();
423    csv.setDoingQuotes(false);
424    PreparedStatement pstmt = con.prepareStatement("INSERT INTO `DrugStrengths` (`drug_concept_id`, `ingredient_concept_id`, `amount_value`, `amount_unit_concept_id`, `numerator_value`, `numerator_unit_concept_id`, `denominator_value`, "
425        + "`denominator_unit_concept_id`, `box_size`, `valid_start_date`, `valid_end_date`, `invalid_reason`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
426    while (csv.line()) {
427      try {
428        pstmt.setString(1, csv.cell("drug_concept_id"));
429        pstmt.setString(2, csv.cell("ingredient_concept_id"));
430        pstmt.setString(3, csv.cell("amount_value"));
431        pstmt.setString(4, csv.cell("amount_unit_concept_id"));
432        pstmt.setString(5, csv.cell("numerator_value"));
433        pstmt.setString(6, csv.cell("numerator_unit_concept_id"));
434        pstmt.setString(7, csv.cell("denominator_value"));
435        pstmt.setString(8, csv.cell("denominator_unit_concept_id"));
436        pstmt.setString(9, csv.cell("box_size"));
437        pstmt.setString(10, date(csv.cell("valid_start_date")));
438        pstmt.setString(11, date(csv.cell("valid_end_date")));
439        pstmt.setString(11, csv.cell("invalid_reason"));
440        pstmt.executeUpdate();
441      } catch (Exception e) {
442        t.error(e.getMessage());
443      }
444      t.step();
445    }
446    csv.close();
447    t.done();
448
449  }
450
451  private int dmax1(int lid, String cell) {
452    int i = cell == null? 0 : cell.indexOf('.');
453    return i > lid ? i : lid;
454  }
455
456  private int dmax2(int lid, String cell) {
457    int i = cell == null? 0 : cell.length() - cell.indexOf('.') - 1;
458    return i > lid ? i : lid;
459  }
460
461  private void processConcepts(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
462    Tracker t = new Tracker("Concepts", 5617348);
463    if (!process) {
464      t.skip();
465      return;
466    }
467
468    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT.csv")));
469    csv.setDelimiter('\t');
470    csv.readHeaders();
471    csv.setDoingQuotes(false);
472    int lname = 0;
473    int lstd = 0;
474    int lcode = 0;
475    int lreason = 0;
476    t.scan();
477    while (csv.line()) {
478      lname = max(lname, csv.cell("concept_name"));
479      lstd = max(lstd, csv.cell("standard_concept"));
480      lcode = max(lcode, csv.cell("concept_code"));
481      lreason = max(lreason, csv.cell("invalid_reason"));
482      t.step();
483    }
484    csv.close();
485    t.process();
486
487    Statement stmt = con.createStatement();
488    stmt.execute("CREATE TABLE `Concepts` (\r\n"+
489        "    `concept_id` bigint NOT NULL,\r\n"+
490        "    `concept_name` varchar("+lname+") DEFAULT NULL,\r\n"+
491        "    `domain_id` bigint DEFAULT NULL,\r\n"+
492        "    `vocabulary_id` bigint DEFAULT NULL,\r\n"+
493        "    `concept_class_id` bigint DEFAULT NULL,\r\n"+
494        "    `standard_concept` varchar("+lstd+") DEFAULT NULL,\r\n"+
495        "    `concept_code` varchar("+lcode+") DEFAULT NULL,\r\n"+
496        "    `valid_start_date` date DEFAULT NULL,\r\n"+
497        "    `valid_end_date` date DEFAULT NULL,\r\n"+
498        "    `invalid_reason` varchar("+lreason+") DEFAULT NULL,\r\n"+
499        "    PRIMARY KEY (`concept_id`)\r\n"+
500        "  ) \r\n"+
501        "\r\n");
502
503    stmt.execute("CREATE INDEX `ConceptDomain` on Concepts (`domain_id`)");
504    stmt.execute("CREATE INDEX `ConceptVocabulary` on Concepts (`vocabulary_id`,`concept_code`)");
505    stmt.execute("CREATE INDEX `ConceptClass` on Concepts (`concept_class_id`)");
506
507    csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT.csv")));
508    csv.setDelimiter('\t');
509    csv.readHeaders();
510    csv.setDoingQuotes(false);
511
512    PreparedStatement pstmt = con.prepareStatement(
513        "INSERT INTO `Concepts` (`concept_id`, `concept_name`, `domain_id`, `vocabulary_id`, `concept_class_id`, `standard_concept`, `concept_code`, `valid_start_date`, `valid_end_date`, `invalid_reason`) "+
514        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); 
515    while (csv.line()) {
516      if (conceptFilter == null || conceptFilter.contains(csv.cell("concept_id")) || isMetaConcept(csv.cell("concept_id"), csv.cell("domain_id"))) {
517        try {
518          pstmt.setString(1, csv.cell("concept_id"));
519          pstmt.setString(2, csv.cell("concept_name"));
520          pstmt.setString(3, domains.get(csv.cell("domain_id")));
521          pstmt.setString(4, vocabularies.get(csv.cell("vocabulary_id")));
522          pstmt.setString(5, classes.get(csv.cell("concept_class_id")));
523          pstmt.setString(6, csv.cell("standard_concept"));
524          pstmt.setString(7, csv.cell("concept_code"));
525          pstmt.setString(8, date(csv.cell("valid_start_date")));
526          pstmt.setString(9, date(csv.cell("valid_end_date")));
527          pstmt.setString(10, csv.cell("invalid_reason"));
528          pstmt.executeUpdate();
529        } catch (Exception e) {
530          t.error(e.getMessage());
531        }
532      }
533      t.step();
534    }
535    csv.close();    
536    t.done();
537  }
538
539  private boolean isMetaConcept(String cell, String domain) {
540    return domains.containsValue(cell) || vocabularies.containsValue(cell) || "Language".equals(domain); 
541  }
542
543  private void processConceptSynonyms(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
544    Tracker t = new Tracker("ConceptSynonyms", 1933498);
545    if (!process) {
546      t.skip();
547      return;
548    }    
549    t.scan();
550
551    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT_SYNONYM.csv")));
552    csv.setDelimiter('\t');
553    csv.readHeaders();
554    csv.setDoingQuotes(false);
555    int lname = 0;
556    while (csv.line()) {
557      lname = max(lname, csv.cell("concept_synonym_name"));
558      t.step();
559    }
560    csv.close();
561    t.process();
562
563    Statement stmt = con.createStatement();
564    stmt.execute("CREATE TABLE `ConceptSynonyms` (\r\n"+
565        "  `concept_id` bigint NOT NULL,\r\n"+
566        "  `concept_synonym_name` varchar("+lname+") DEFAULT NULL,\r\n"+
567        "  `language_concept_id` bigint DEFAULT NULL\r\n"+
568        ") \r\n"+
569        "\r\n");
570    stmt.execute("CREATE INDEX `SynonymId` on ConceptSynonyms (`concept_id`)");
571    stmt.execute("CREATE INDEX `SynonymLang` on ConceptSynonyms (`language_concept_id`)");
572
573    csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT_SYNONYM.csv")));
574    csv.setDelimiter('\t');
575    csv.readHeaders();
576    csv.setDoingQuotes(false);
577    
578    PreparedStatement pstmt = con.prepareStatement("INSERT INTO `ConceptSynonyms` (`concept_id`, `concept_synonym_name`, `language_concept_id`) VALUES (?, ?, ?)");
579    while (csv.line()) {
580      if (conceptFilter == null || conceptFilter.contains(csv.cell("concept_id")) || isMetaConcept(csv.cell("concept_id"), null)) {
581        try {
582          pstmt.setString(1, csv.cell("concept_id"));
583          pstmt.setString(2, csv.cell("concept_synonym_name"));
584          pstmt.setString(3, csv.cell("language_concept_id"));
585          pstmt.executeUpdate();
586        } catch (Exception e) {
587          t.error(e.getMessage());
588        }
589      }
590      t.step();
591    }
592    csv.close();
593    t.done();
594  }
595
596
597  private void processConceptAncestors(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
598    Tracker t = new Tracker("ConceptAncestors", 67425885);
599    if (!process) {
600      t.skip();
601      return;
602    }
603
604    t.process();
605    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT_ANCESTOR.csv")));
606    csv.setDelimiter('\t');
607    csv.readHeaders();
608    csv.setDoingQuotes(false);
609    con.createStatement().execute("CREATE TABLE `ConceptAncestors` (\r\n"+
610        "    `ancestor_concept_id` bigint NOT NULL,\r\n"+
611        "    `descendant_concept_id` bigint NOT NULL,\r\n"+
612        "    `min_levels_of_separation` int DEFAULT NULL,\r\n"+
613        "    `max_levels_of_separation` int DEFAULT NULL,\r\n"+
614        "    PRIMARY KEY (`ancestor_concept_id`,`descendant_concept_id`)\r\n"+
615        "  ) \r\n"+
616        "\r\n");
617    
618    PreparedStatement pstmt = con.prepareStatement("INSERT INTO `ConceptAncestors` (`ancestor_concept_id`, `descendant_concept_id`, `min_levels_of_separation`, `max_levels_of_separation`) VALUES (?, ?, ?, ?)");
619    while (csv.line()) {
620      try {
621        pstmt.setString(1, csv.cell("ancestor_concept_id"));
622        pstmt.setString(2, csv.cell("descendant_concept_id"));
623        pstmt.setString(3, csv.cell("min_levels_of_separation"));
624        pstmt.setString(4, csv.cell("max_levels_of_separation"));
625        pstmt.executeUpdate();
626      } catch (Exception e) {
627        t.error(e.getMessage());
628      }
629      t.step();
630    }
631    csv.close();
632    t.done();
633  }
634
635
636  private void processConceptRelationships(String folder, boolean process) throws FHIRException, FileNotFoundException, IOException, SQLException {
637    Tracker t = new Tracker("ConceptRelationships", 47000000);
638    if (!process) {
639      t.skip();
640      return;
641    }
642
643    t.scan();
644    CSVReader csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT_RELATIONSHIP.csv")));
645    csv.setDelimiter('\t');
646    csv.readHeaders();
647    csv.setDoingQuotes(false);
648    int lreason = 0;
649    while (csv.line()) {
650      lreason = max(lreason, csv.cell("invalid_reason"));
651      t.step();
652    }
653    csv.close();
654    t.process();
655
656    Statement stmt = con.createStatement();
657    stmt.execute("CREATE TABLE `ConceptRelationships` (\r\n"+
658        "  `concept_id_1` bigint NOT NULL,\r\n"+
659        "  `concept_id_2` bigint NOT NULL,\r\n"+
660        "  `relationship_id` bigint NOT NULL,\r\n"+
661        "  `valid_start_date` date DEFAULT NULL,\r\n"+
662        "  `valid_end_date` date DEFAULT NULL,\r\n"+
663        "  `invalid_reason` varchar("+lreason+") DEFAULT NULL)\r\n"+
664        "  \r\n");
665
666    stmt.execute("CREATE INDEX `Reverse` on ConceptRelationships (`concept_id_2`,`concept_id_1`,`relationship_id`)");
667    stmt.execute("CREATE INDEX `Forward` on ConceptRelationships (`concept_id_1`,`concept_id_2`,`relationship_id`)");  
668//  stmt.execute("CREATE INDEX `type1` on ConceptRelationships (`relationship_id`,`concept_id_1`,`concept_id_2`)");
669//  stmt.execute("CREATE INDEX `type2` on ConceptRelationships (`relationship_id`,`concept_id_2`,`concept_id_1`)");
670
671    csv = new CSVReader(ManagedFileAccess.inStream(Utilities.path(folder, "CONCEPT_RELATIONSHIP.csv")));
672    csv.setDelimiter('\t');
673    csv.readHeaders();
674    csv.setDoingQuotes(false);
675
676    PreparedStatement pstmt = con.prepareStatement("INSERT INTO `ConceptRelationships` (`concept_id_1`, `concept_id_2`, `relationship_id`, `valid_start_date`, `valid_end_date`, `invalid_reason`) VALUES (?, ?, ?, ?, ?, ?)");
677    while (csv.line()) {
678      if (conceptFilter == null || ((conceptFilter.contains(csv.cell("concept_id_1")) || isMetaConcept(csv.cell("concept_id_1"), null)) && (conceptFilter.contains(csv.cell("concept_id_2")) || isMetaConcept(csv.cell("concept_id_2"), null)))) {
679        try {
680          pstmt.setString(1, csv.cell("concept_id_1"));
681          pstmt.setString(2, csv.cell("concept_id_2"));
682          pstmt.setString(3, relationships.get(csv.cell("relationship_id")));
683          pstmt.setString(4, csv.cell("valid_start_date"));
684          pstmt.setString(5, date(csv.cell("valid_end_date")));
685          pstmt.setString(6, date(csv.cell("invalid_reason")));
686          pstmt.executeUpdate();
687        } catch (Exception e) {
688          t.error(e.getMessage());
689        }
690      }
691      t.step();
692    }
693    csv.close();
694    t.done();
695
696  }
697
698
699  private String date(String cell) {
700    return cell;
701  }
702
703  private String sw(String value) {
704    if (value == null) {
705      return  "null";
706    }
707    StringBuilder b = new StringBuilder();
708    b.append('"');
709    for (char ch : value.toCharArray()) {
710      if (ch == '"') {
711        b.append('"');        
712      }
713      b.append(ch);
714    }
715    b.append('"');
716    return b.toString();
717  }
718
719  
720}