georgysavva / scany

Library for scanning data from a database into Go structs and more
MIT License
1.29k stars 68 forks source link

cannot scan into struct - columnToFieldIndex does not get populated with column names #47

Closed siwik75 closed 2 years ago

siwik75 commented 3 years ago

Similar to the example given in readme, I tried to tailor it to my case, using postgres (local db) and pgx module v4

Here I tried the two versions of select with 4 or just 2 columns which would fit into the FanOutStatus struct

package` pgrds

import (
   "context"
   "fmt"
   "github.com/georgysavva/scany/pgxscan"
   "github.com/jackc/pgx/v4/pgxpool"
   "os"
)

//const GET_FANOUT_STATUS_SQL = "select requestid,requestcount,status,count(*) as totalrequest from srepfanoutstatus where requestid=$1 "+
//                     "group by requestid,requestcount,status;"

const GET_FANOUT_STATUS_SQL = "SELECT requestid,requestcount FROM srepfanoutstatus"

type FanOutStatus struct {
   RequestId string
   RequestCount int
   //status string
   //totalrequest int
}

func GetFanoutRequestStatus(request_id string) []*FanOutStatus {
   // urlExample := "postgres://username:password@localhost:5432/database_name"
   conn, err := pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL"))
   if err != nil {
      fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
      os.Exit(1)
   }

   var records []*FanOutStatus
   //var RequestId string
   //var RequestCount int
   //var Status string
   //var TotalRequest int
   //rows, err := conn.Query(context.Background(), GET_FANOUT_STATUS_SQL, "1234")
   err = pgxscan.Select(context.Background(), conn, &records, GET_FANOUT_STATUS_SQL)
   if err != nil {
      fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
      os.Exit(1)
   }

   for rec := range records {
      fmt.Println(rec)
   }

   return records
}

ERROR when calling the method is QueryRow failed: scany: column: 'requestid': no corresponding field found, or it's unexported in pgrds.FanOutStatus

from debugging, found that issue triggers at dbscan.go

func (rs *RowScanner) scanStruct(structValue reflect.Value) error {
   scans := make([]interface{}, len(rs.columns))
   for i, column := range rs.columns {
      fieldIndex, ok := rs.columnToFieldIndex[column]
...

line 294

rs(RowScanner) is populated with all the columns but not the map, which is empty.

type RowScanner struct {
   rows               Rows
   columns            []string
   columnToFieldIndex map[string][]int
   mapElementType     reflect.Type
   started            bool
   start              startScannerFunc
}
georgysavva commented 3 years ago

Hello! Thank you for providing all that information. I see that your struct field doesn't have the db tag, without a tag scany translates the field name to snake case, so RequestId -> request_id, but in the SQL select you have requestid column.

Please check this documentation section for details: https://pkg.go.dev/github.com/georgysavva/scany@v0.2.8/dbscan#hdr-Mapping_struct_field_to_database_column

lamari commented 2 years ago

Hello! Why is this issue still Open ?

georgysavva commented 2 years ago

@lamari I didn't close it because the author of the issue hasn't replied yet. But I think you are right and we can close it due to inactivity. Since it seems there is no problem on the scany side.