Why not use an interface? type TableSaver func (db *DB) or type TableSaver func (tx *Tx) // depending on your needs
Allowing you to: func (t *Table) SaveTable (...) {} Which in your example if you wanted use a different SaveTable implementation for OtherTable you could. Otherwise it would just inherit it from Table. Or am I missing something here? Chris On Friday, 5 January 2018 16:11:53 UTC, Manlio Perillo wrote: > > Il giorno venerdì 5 gennaio 2018 16:57:04 UTC+1, Ayan George ha scritto: >> >> >> >> On 01/05/2018 10:16 AM, Manlio Perillo wrote: >> > Recently I have developed a few web applications in Go, using a >> > PostgreSQL database, but I have yet understand the best way to use >> > the database/sql package. >> > >> >> I don't know how you're serving web pages but I typically use net/http. >> This also means that I typically build an http.Server. This requires >> that I create a type that conforms to the http.Handler interface. >> > > Yes, I use the standard net/http interface, without frameworks (but I use > a simple toolkit written by me). > >> >> You can use this type to pass around all of the data you need, including >> sql.DB instances, log.Logger, etc. >> >> So here's the skeleton of what I normally do. I haven't tested this -- >> this is just to get the point across. Finally, this may be completely >> off base. I'm open to any criticisms etc. anyone may have. >> >> package main >> >> import ( >> "database/sql" >> _ "github.com/lib/pq" >> "log" >> "net/http" >> "time" >> ) >> >> type app struct { >> db *sql.DB >> } >> >> func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) { >> // here we can use all of the fields of our app struct -- including >> the db! >> >> row := db.QueryRow("select current_timestamp;") >> >> var time string >> err := row.Scan(&time) >> >> if err != nil { >> // handle the error. maybe log it? i typically >> // create a log.Logger instance in my app and use it >> // at times like these. >> return >> } >> >> w.Write([]byte("<h1>hello, world!</h1>")) >> } >> >> func main() { >> db, err := sql.Open("postgres", "...") >> >> if err != nil { >> log.Fatal(err) >> } >> >> if err := db.Ping(); err != nil { >> log.Fatal(err) >> } >> >> myapp := app{ >> db: db, >> } >> >> srv := http.Server{ >> Addr: ":8080", >> ReadTimeout: 1 * time.Second, >> WriteTimeout: 1 * time.Second, >> Handler: &myapp, >> } >> >> log.Fatal(srv.ListenAndServe()) >> } >> > > Thanks, this is a very good solution. > > Currently I'm using something different, however. > I have a package that exports the same API as database/sql, but as free > functions using a global *DB configured when loading a configuration file. > > However the question is the same, and it is how and what to pass to > functions that need a connection to the database. > > Passing *DB is no good; take as an example a "generic" package having > > type Table struct { > A int > B string > } > > func SaveTable(t *Table, db *DB) ... > > or > func SaveTable(t *Table, tx *Tx) ... > > The function does not need to know if it is inside a transaction; it is > the responsibility of the caller. > > However consider a package with > > type Table struct { > A int > B string > } > > type OtherTable struct { > Table > C float64 > B bool > } > > > Now the function SaveOtherTable may want to use a transaction to save > Table and OtherTable separately. > You surely can not pass a *Tx, since it does not support nested > transactions. > > > > Thanks > Manlio Perillo > > > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.