github.com/andrewrech/ih-abstract@v0.0.0-20210322142951-2fec1c8d0f38/read.go (about)

     1  package main
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/csv"
     6  	"errors"
     7  	"io"
     8  	"log"
     9  	"os"
    10  
    11  	_ "github.com/denisenkom/go-mssqldb" // sql driver
    12  )
    13  
    14  // read reads raw input data.
    15  func read(f flags, in *os.File) (r rawRecords) {
    16  	log.Println("initializing records map")
    17  
    18  	if *f.sql {
    19  		log.Println("reading Sql")
    20  
    21  		db, err := connect(*f.config)
    22  		if err != nil {
    23  			log.Fatalln(err)
    24  		}
    25  		defer db.Close()
    26  
    27  		r = DB(*f.config, db)
    28  	}
    29  
    30  	if !(*f.sql) {
    31  		log.Println("reading Stdin")
    32  
    33  		r = readCSV(in)
    34  	}
    35  
    36  	return r
    37  }
    38  
    39  // readSQLRows reads rows of strings from an SQL database.
    40  func readSQLRows(rows *sql.Rows) (r rawRecords) {
    41  	var buf int64 = 2e7
    42  
    43  	// initialize channels
    44  	r.out = make(chan []string, buf)
    45  	r.done = make(chan struct{})
    46  
    47  	var err error
    48  	r.header, err = rows.Columns()
    49  	if err != nil {
    50  		log.Fatalln(err)
    51  	}
    52  
    53  	// slice of byte slices of correct length
    54  	rawResult := make([]sql.NullString, len(r.header))
    55  	// string slice of correct length
    56  	result := make([]string, len(r.header))
    57  	// destination interface
    58  	dest := make([]interface{}, len(r.header))
    59  
    60  	// add pointers to destination
    61  	for i := range result {
    62  		dest[i] = &rawResult[i]
    63  	}
    64  
    65  	var counter int64
    66  	stopCounter := make(chan struct{})
    67  	count(&counter, "read (sql)", stopCounter)
    68  
    69  	go func() {
    70  		for rows.Next() {
    71  			// fill destination
    72  			err = rows.Scan(dest...)
    73  			if err != nil {
    74  				log.Fatalln(err)
    75  			}
    76  
    77  			counter++
    78  
    79  			for i, raw := range rawResult {
    80  				// handle nil type with conversion to ""
    81  				if raw.Valid {
    82  					result[i] = raw.String
    83  				}
    84  			}
    85  
    86  			r.out <- result
    87  		}
    88  
    89  		err = rows.Err()
    90  		if err != nil {
    91  			log.Fatalln("error encountered during iteration:", rows.Err())
    92  		}
    93  
    94  		close(r.out)
    95  		stopCounter <- struct{}{}
    96  		r.done <- struct{}{}
    97  	}()
    98  
    99  	return r
   100  }
   101  
   102  // readCSV reads records from a CSV file.
   103  func readCSV(in io.Reader) (r rawRecords) {
   104  	var buf int64 = 2e7
   105  
   106  	// initialize channels
   107  	r.out = make(chan []string, buf)
   108  	r.done = make(chan struct{})
   109  
   110  	reader := csv.NewReader(in)
   111  	reader.LazyQuotes = true
   112  
   113  	var err error
   114  	r.header, err = reader.Read()
   115  	if err != nil {
   116  		log.Fatal(err)
   117  	}
   118  
   119  	var counter int64
   120  	stopCounter := make(chan struct{})
   121  	count(&counter, "read (csv)", stopCounter)
   122  
   123  	// process records
   124  	go func() {
   125  		for {
   126  			l, err := reader.Read()
   127  
   128  			counter++
   129  
   130  			switch {
   131  			case errors.Is(err, io.EOF):
   132  				r.done <- struct{}{}
   133  
   134  				close(r.out)
   135  
   136  			case err != nil:
   137  				log.Fatal(err)
   138  
   139  			default:
   140  				r.out <- l
   141  			}
   142  		}
   143  	}()
   144  
   145  	stopCounter <- struct{}{}
   146  
   147  	return r
   148  }
   149  
   150  // headerParse parses input data column names.
   151  func headerParse(h []string) (colNames map[string]int) {
   152  	colNames = make(map[string]int)
   153  
   154  	for i, s := range h {
   155  		colNames[s] = i
   156  	}
   157  
   158  	return
   159  }