<commit_before>/*
Copyright 2016 The Fission Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package router

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"

	"github.com/platform9/fission"
	poolmgrClient "github.com/platform9/fission/poolmgr/client"
)

type functionHandler struct {
	fmap     *functionServiceMap
	poolmgr  *poolmgrClient.Client
	Function fission.Metadata
}

func (fh *functionHandler) getServiceForFunction() (*url.URL, error) {
	// call poolmgr, get a url for a function
	svcName, err := fh.poolmgr.GetServiceForFunction(&fh.Function)
	if err != nil {
		return nil, err
	}
	svcUrl, err := url.Parse(fmt.Sprintf("http://%v", svcName))
	if err != nil {
		return nil, err
	}
	return svcUrl, nil
}

func (fh *functionHandler) handler(responseWriter http.ResponseWriter, request *http.Request) {
	serviceUrl, err := fh.fmap.lookup(&fh.Function)
	if err != nil {
		// Cache miss: request the Pool Manager to make a new service.
		log.Printf("Not cached, getting new service for %v", fh.Function)
		serviceUrl, poolErr := fh.getServiceForFunction()
		if poolErr != nil {
			log.Printf("Failed to get service for function (%v,%v): %v",
				fh.Function.Name, fh.Function.Uid, poolErr)
			// We might want a specific error code or header for fission
			// failures as opposed to user function bugs.
			http.Error(responseWriter, poolErr.Error(), 500)
			return
		}

		// add it to the map
		fh.fmap.assign(&fh.Function, serviceUrl)
	}

	// Proxy off our request to the serviceUrl, and send the response back.
	// TODO: As an optimization we may want to cache proxies too -- this might get us
	// connection reuse and possibly better performance
	director := func(req *http.Request) {
		log.Printf("Proxying request for %v", req.URL)

		// send this request to serviceurl
		req.URL.Scheme = serviceUrl.Scheme
		req.URL.Host = serviceUrl.Host
		req.URL.Path = serviceUrl.Path
		// leave the query string intact (req.URL.RawQuery)

		if _, ok := req.Header["User-Agent"]; !ok {
			// explicitly disable User-Agent so it's not set to default value
			req.Header.Set("User-Agent", "")
		}
	}
	proxy := &httputil.ReverseProxy{Director: director}
	proxy.ServeHTTP(responseWriter, request)

	// TODO: handle failures and possibly retry here.
}
<commit_msg>Don't put internal fission error details in responses<commit_after>/*
Copyright 2016 The Fission Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package router

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"

	"github.com/platform9/fission"
	poolmgrClient "github.com/platform9/fission/poolmgr/client"
)

type functionHandler struct {
	fmap     *functionServiceMap
	poolmgr  *poolmgrClient.Client
	Function fission.Metadata
}

func (fh *functionHandler) getServiceForFunction() (*url.URL, error) {
	// call poolmgr, get a url for a function
	svcName, err := fh.poolmgr.GetServiceForFunction(&fh.Function)
	if err != nil {
		return nil, err
	}
	svcUrl, err := url.Parse(fmt.Sprintf("http://%v", svcName))
	if err != nil {
		return nil, err
	}
	return svcUrl, nil
}

func (fh *functionHandler) handler(responseWriter http.ResponseWriter, request *http.Request) {
	serviceUrl, err := fh.fmap.lookup(&fh.Function)
	if err != nil {
		// Cache miss: request the Pool Manager to make a new service.
		log.Printf("Not cached, getting new service for %v", fh.Function)
		serviceUrl, poolErr := fh.getServiceForFunction()
		if poolErr != nil {
			log.Printf("Failed to get service for function (%v,%v): %v",
				fh.Function.Name, fh.Function.Uid, poolErr)
			// We might want a specific error code or header for fission
			// failures as opposed to user function bugs.
			http.Error(responseWriter, "Internal server error (fission)", 500)
			return
		}

		// add it to the map
		fh.fmap.assign(&fh.Function, serviceUrl)
	}

	// Proxy off our request to the serviceUrl, and send the response back.
	// TODO: As an optimization we may want to cache proxies too -- this might get us
	// connection reuse and possibly better performance
	director := func(req *http.Request) {
		log.Printf("Proxying request for %v", req.URL)

		// send this request to serviceurl
		req.URL.Scheme = serviceUrl.Scheme
		req.URL.Host = serviceUrl.Host
		req.URL.Path = serviceUrl.Path
		// leave the query string intact (req.URL.RawQuery)

		if _, ok := req.Header["User-Agent"]; !ok {
			// explicitly disable User-Agent so it's not set to default value
			req.Header.Set("User-Agent", "")
		}
	}
	proxy := &httputil.ReverseProxy{Director: director}
	proxy.ServeHTTP(responseWriter, request)

	// TODO: handle failures and possibly retry here.
}
<|endoftext|>


<commit_before>package movieds

import (
	"context"
	"database/sql"

	"github.com/gilcrest/go-api-basic/app"
	"github.com/gilcrest/go-api-basic/datastore"
	"github.com/gilcrest/go-api-basic/domain/errs"
	"github.com/gilcrest/go-api-basic/domain/movie"
	"github.com/google/uuid"
)

// MovieDS is the interface for the persistence layer for a movie
type MovieDS interface {
	Create(context.Context, *movie.Movie) error
	FindByID(context.Context, string) (*movie.Movie, error)
	FindAll(context.Context) ([]*movie.Movie, error)
	Update(context.Context, *movie.Movie) error
	Delete(context.Context, *movie.Movie) error
}

// NewMovieDS sets up either a concrete MovieDB or a MockMovieDB
// depending on the underlying struct of the Datastore passed in
func NewMovieDS(app *app.Application) (MovieDS, error) {
	const op errs.Op = "movieds/NewMovieDS"

	// Use a type switch to determine if the app datastore is a Mock
	// Datastore, if so, then return MockMovieDB, otherwise use
	// composition to add the Datastore to the MovieDB struct
	switch ds := app.DS.(type) {
	case *datastore.MockDS:
		return &MockMovieDB{}, nil
	case *datastore.DS:
		return &MovieDB{DS: ds}, nil
	default:
		return nil, errs.E(op, "Unknown type for datastore.Datastore")
	}
}

// MovieDB is the database implementation for CRUD operations for a movie
type MovieDB struct {
	*datastore.DS
}

// Create inserts a record in the user table using a stored function
func (mdb *MovieDB) Create(ctx context.Context, m *movie.Movie) error {
	const op errs.Op = "movie/Movie.createDB"

	// Prepare the sql statement using bind variables
	stmt, err := mdb.Tx.PrepareContext(ctx, `
	select o_create_timestamp,
		   o_update_timestamp
	  from demo.create_movie (
		p_id => $1,
		p_extl_id => $2,
		p_title => $3,
		p_year => $4,
		p_rated => $5,
		p_released => $6,
		p_run_time => $7,
		p_director => $8,
		p_writer => $9,
		p_create_client_id => $10,
		p_create_user_id => $11)`)

	if err != nil {
		return errs.E(op, err)
	}
	defer stmt.Close()

	// At some point, I will add a whole user flow, but for now
	// faking a user uuid....
	fakeUserID := uuid.New()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.ID,       //$1
		m.ExtlID,   //$2
		m.Title,    //$3
		m.Year,     //$4
		m.Rated,    //$5
		m.Released, //$6
		m.RunTime,  //$7
		m.Director, //$8
		m.Writer,   //$9
		fakeUserID, //$10
		fakeUserID) //$11

	if err != nil {
		return errs.E(op, err)
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.CreateTimestamp, &m.UpdateTimestamp); err != nil {
			return errs.E(op, err)
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(op, err)
	}

	return nil
}

// Update updates a record in the database using the external ID of
// the Movie
func (mdb *MovieDB) Update(ctx context.Context, m *movie.Movie) error {
	const op errs.Op = "movieds/MockMovieDB.Update"

	// Prepare the sql statement using bind variables
	stmt, err := mdb.Tx.PrepareContext(ctx, `
	update demo.movie
	   set title = $1,
		   year = $2,
		   rated = $3,
		   released = $4,
		   run_time = $5,
		   director = $6,
		   writer = $7,
		   update_user_id = $8,
		   update_timestamp = $9
	 where extl_id = $10
 returning movie_id, create_timestamp`)

	if err != nil {
		return errs.E(op, err)
	}
	defer stmt.Close()

	// At some point, I will add a whole user flow, but for now
	// faking a user uuid....
	fakeUserID := uuid.New()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.Title,           //$1
		m.Year,            //$2
		m.Rated,           //$3
		m.Released,        //$4
		m.RunTime,         //$5
		m.Director,        //$6
		m.Writer,          //$7
		fakeUserID,        //$8
		m.UpdateTimestamp, //$9
		m.ExtlID)          //$10

	if err != nil {
		return errs.E(op, err)
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.ID, &m.CreateTimestamp); err != nil {
			return errs.E(op, err)
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(op, err)
	}

	// If the table's primary key is not returned as part of the
	// RETURNING clause, this means the row was not actually updated.
	// The update request does not contain this key (I don't believe
	// in exposing primary keys), so this is a way of returning data
	// from an update statement and checking whether or not the
	// update was actually successful. Typically you would use
	// db.Exec and check RowsAffected (like I do in delete), but I
	// wanted to show an alternative which can be useful here
	if m.ID == uuid.Nil {
		return errs.E(op, errs.Database, "Invalid ID - no records updated")
	}

	return nil
}

// FindByID returns a Movie struct to populate the response
func (mdb *MovieDB) FindByID(ctx context.Context, extlID string) (*movie.Movie, error) {
	const op errs.Op = "movieds/MovieDB.FindByID"

	// Prepare the sql statement using bind variables
	row := mdb.DB.QueryRowContext(ctx,
		`select movie_id,
				extl_id,
				title,
				year,
				rated,
				released,
				run_time,
				director,
				writer,
				create_timestamp,
				update_timestamp
		   from demo.movie m
		  where extl_id = $1`, extlID)

	m := new(movie.Movie)
	err := row.Scan(
		&m.ID,
		&m.ExtlID,
		&m.Title,
		&m.Year,
		&m.Rated,
		&m.Released,
		&m.RunTime,
		&m.Director,
		&m.Writer,
		&m.CreateTimestamp,
		&m.UpdateTimestamp)

	if err == sql.ErrNoRows {
		return nil, errs.E(op, errs.NotExist, err)
	} else if err != nil {
		return nil, errs.E(op, err)
	}

	return m, nil
}

// FindAll returns a slice of Movie structs to populate the response
func (mdb *MovieDB) FindAll(ctx context.Context) ([]*movie.Movie, error) {
	const op errs.Op = "movieds/MovieDB.FindAll"

	// declare a slice of pointers to movie.Movie
	var s []*movie.Movie

	// use QueryContext to get back sql.Rows
	rows, err := mdb.DB.QueryContext(ctx,
		`select movie_id,
				extl_id,
				title,
				year,
				rated,
				released,
				run_time,
				director,
				writer,
				create_timestamp,
				update_timestamp
		   from demo.movie m`)
	if err != nil {
		return nil, errs.E(op, errs.Database, err)
	}
	defer rows.Close()

	// iterate through each row and scan the results into
	// a movie.Movie. Append movie.Movie to the slice
	// defined above
	for rows.Next() {
		m := new(movie.Movie)
		err = rows.Scan(
			&m.ID,
			&m.ExtlID,
			&m.Title,
			&m.Year,
			&m.Rated,
			&m.Released,
			&m.RunTime,
			&m.Director,
			&m.Writer,
			&m.CreateTimestamp,
			&m.UpdateTimestamp)

		if err == sql.ErrNoRows {
			return nil, errs.E(op, errs.NotExist, err)
		} else if err != nil {
			return nil, errs.E(op, err)
		}

		s = append(s, m)
	}
	// Rows.Err will report the last error encountered by Rows.Scan.
	err = rows.Err()
	if err != nil {
		return nil, errs.E(op, errs.Database, err)
	}

	// return the slice
	return s, nil
}

// Delete removes the Movie record from the table
func (mdb *MovieDB) Delete(ctx context.Context, m *movie.Movie) error {
	const op errs.Op = "movie/MovieDB.Delete"

	result, execErr := mdb.Tx.ExecContext(ctx,
		`DELETE from demo.movie
		  WHERE movie_id = ?`, m.ID)
	if execErr != nil {
		return errs.E(op, errs.Database, execErr)
	}

	// Only 1 row should be deleted, check the result count to
	// ensure this is correct
	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return errs.E(op, errs.Database, err)
	}
	if rowsAffected == 0 {
		return errs.E(op, errs.Database, "No Rows Deleted")
	} else if rowsAffected > 1 {
		return errs.E(op, errs.Database, "Too Many Rows Deleted")
	}

	return nil
}
<commit_msg>fix ? to $1 for postgres<commit_after>package movieds

import (
	"context"
	"database/sql"

	"github.com/gilcrest/go-api-basic/app"
	"github.com/gilcrest/go-api-basic/datastore"
	"github.com/gilcrest/go-api-basic/domain/errs"
	"github.com/gilcrest/go-api-basic/domain/movie"
	"github.com/google/uuid"
)

// MovieDS is the interface for the persistence layer for a movie
type MovieDS interface {
	Create(context.Context, *movie.Movie) error
	FindByID(context.Context, string) (*movie.Movie, error)
	FindAll(context.Context) ([]*movie.Movie, error)
	Update(context.Context, *movie.Movie) error
	Delete(context.Context, *movie.Movie) error
}

// NewMovieDS sets up either a concrete MovieDB or a MockMovieDB
// depending on the underlying struct of the Datastore passed in
func NewMovieDS(app *app.Application) (MovieDS, error) {
	const op errs.Op = "movieds/NewMovieDS"

	// Use a type switch to determine if the app datastore is a Mock
	// Datastore, if so, then return MockMovieDB, otherwise use
	// composition to add the Datastore to the MovieDB struct
	switch ds := app.DS.(type) {
	case *datastore.MockDS:
		return &MockMovieDB{}, nil
	case *datastore.DS:
		return &MovieDB{DS: ds}, nil
	default:
		return nil, errs.E(op, "Unknown type for datastore.Datastore")
	}
}

// MovieDB is the database implementation for CRUD operations for a movie
type MovieDB struct {
	*datastore.DS
}

// Create inserts a record in the user table using a stored function
func (mdb *MovieDB) Create(ctx context.Context, m *movie.Movie) error {
	const op errs.Op = "movie/Movie.createDB"

	// Prepare the sql statement using bind variables
	stmt, err := mdb.Tx.PrepareContext(ctx, `
	select o_create_timestamp,
		   o_update_timestamp
	  from demo.create_movie (
		p_id => $1,
		p_extl_id => $2,
		p_title => $3,
		p_year => $4,
		p_rated => $5,
		p_released => $6,
		p_run_time => $7,
		p_director => $8,
		p_writer => $9,
		p_create_client_id => $10,
		p_create_user_id => $11)`)

	if err != nil {
		return errs.E(op, err)
	}
	defer stmt.Close()

	// At some point, I will add a whole user flow, but for now
	// faking a user uuid....
	fakeUserID := uuid.New()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.ID,       //$1
		m.ExtlID,   //$2
		m.Title,    //$3
		m.Year,     //$4
		m.Rated,    //$5
		m.Released, //$6
		m.RunTime,  //$7
		m.Director, //$8
		m.Writer,   //$9
		fakeUserID, //$10
		fakeUserID) //$11

	if err != nil {
		return errs.E(op, err)
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.CreateTimestamp, &m.UpdateTimestamp); err != nil {
			return errs.E(op, err)
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(op, err)
	}

	return nil
}

// Update updates a record in the database using the external ID of
// the Movie
func (mdb *MovieDB) Update(ctx context.Context, m *movie.Movie) error {
	const op errs.Op = "movieds/MockMovieDB.Update"

	// Prepare the sql statement using bind variables
	stmt, err := mdb.Tx.PrepareContext(ctx, `
	update demo.movie
	   set title = $1,
		   year = $2,
		   rated = $3,
		   released = $4,
		   run_time = $5,
		   director = $6,
		   writer = $7,
		   update_user_id = $8,
		   update_timestamp = $9
	 where extl_id = $10
 returning movie_id, create_timestamp`)

	if err != nil {
		return errs.E(op, err)
	}
	defer stmt.Close()

	// At some point, I will add a whole user flow, but for now
	// faking a user uuid....
	fakeUserID := uuid.New()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.Title,           //$1
		m.Year,            //$2
		m.Rated,           //$3
		m.Released,        //$4
		m.RunTime,         //$5
		m.Director,        //$6
		m.Writer,          //$7
		fakeUserID,        //$8
		m.UpdateTimestamp, //$9
		m.ExtlID)          //$10

	if err != nil {
		return errs.E(op, err)
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.ID, &m.CreateTimestamp); err != nil {
			return errs.E(op, err)
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(op, err)
	}

	// If the table's primary key is not returned as part of the
	// RETURNING clause, this means the row was not actually updated.
	// The update request does not contain this key (I don't believe
	// in exposing primary keys), so this is a way of returning data
	// from an update statement and checking whether or not the
	// update was actually successful. Typically you would use
	// db.Exec and check RowsAffected (like I do in delete), but I
	// wanted to show an alternative which can be useful here
	if m.ID == uuid.Nil {
		return errs.E(op, errs.Database, "Invalid ID - no records updated")
	}

	return nil
}

// FindByID returns a Movie struct to populate the response
func (mdb *MovieDB) FindByID(ctx context.Context, extlID string) (*movie.Movie, error) {
	const op errs.Op = "movieds/MovieDB.FindByID"

	// Prepare the sql statement using bind variables
	row := mdb.DB.QueryRowContext(ctx,
		`select movie_id,
				extl_id,
				title,
				year,
				rated,
				released,
				run_time,
				director,
				writer,
				create_timestamp,
				update_timestamp
		   from demo.movie m
		  where extl_id = $1`, extlID)

	m := new(movie.Movie)
	err := row.Scan(
		&m.ID,
		&m.ExtlID,
		&m.Title,
		&m.Year,
		&m.Rated,
		&m.Released,
		&m.RunTime,
		&m.Director,
		&m.Writer,
		&m.CreateTimestamp,
		&m.UpdateTimestamp)

	if err == sql.ErrNoRows {
		return nil, errs.E(op, errs.NotExist, err)
	} else if err != nil {
		return nil, errs.E(op, err)
	}

	return m, nil
}

// FindAll returns a slice of Movie structs to populate the response
func (mdb *MovieDB) FindAll(ctx context.Context) ([]*movie.Movie, error) {
	const op errs.Op = "movieds/MovieDB.FindAll"

	// declare a slice of pointers to movie.Movie
	var s []*movie.Movie

	// use QueryContext to get back sql.Rows
	rows, err := mdb.DB.QueryContext(ctx,
		`select movie_id,
				extl_id,
				title,
				year,
				rated,
				released,
				run_time,
				director,
				writer,
				create_timestamp,
				update_timestamp
		   from demo.movie m`)
	if err != nil {
		return nil, errs.E(op, errs.Database, err)
	}
	defer rows.Close()

	// iterate through each row and scan the results into
	// a movie.Movie. Append movie.Movie to the slice
	// defined above
	for rows.Next() {
		m := new(movie.Movie)
		err = rows.Scan(
			&m.ID,
			&m.ExtlID,
			&m.Title,
			&m.Year,
			&m.Rated,
			&m.Released,
			&m.RunTime,
			&m.Director,
			&m.Writer,
			&m.CreateTimestamp,
			&m.UpdateTimestamp)

		if err == sql.ErrNoRows {
			return nil, errs.E(op, errs.NotExist, err)
		} else if err != nil {
			return nil, errs.E(op, err)
		}

		s = append(s, m)
	}
	// Rows.Err will report the last error encountered by Rows.Scan.
	err = rows.Err()
	if err != nil {
		return nil, errs.E(op, errs.Database, err)
	}

	// return the slice
	return s, nil
}

// Delete removes the Movie record from the table
func (mdb *MovieDB) Delete(ctx context.Context, m *movie.Movie) error {
	const op errs.Op = "movie/MovieDB.Delete"

	result, execErr := mdb.Tx.ExecContext(ctx,
		`DELETE from demo.movie
		  WHERE movie_id = $1`, m.ID)
	if execErr != nil {
		return errs.E(op, errs.Database, execErr)
	}

	// Only 1 row should be deleted, check the result count to
	// ensure this is correct
	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return errs.E(op, errs.Database, err)
	}
	if rowsAffected == 0 {
		return errs.E(op, errs.Database, "No Rows Deleted")
	} else if rowsAffected > 1 {
		return errs.E(op, errs.Database, "Too Many Rows Deleted")
	}

	return nil
}
<|endoftext|>


<commit_before>package controllers

import (
	"log"
	"net/http"

	"github.com/nuveo/prest/adapters/postgres"
	"github.com/nuveo/prest/statements"
)

// GetDatabases list all (or filter) databases
func GetDatabases(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	object, err := postgres.Query(statements.Databases)
	if err != nil {
		log.Println(err)
	}

	w.Write(object)
}
<commit_msg>set Header via view<commit_after>package controllers

import (
	"log"
	"net/http"

	"github.com/nuveo/prest/adapters/postgres"
	"github.com/nuveo/prest/statements"
)

// GetDatabases list all (or filter) databases
func GetDatabases(w http.ResponseWriter, r *http.Request) {
	object, err := postgres.Query(statements.Databases)
	if err != nil {
		log.Println(err)
	}

	w.Write(object)
}
<|endoftext|>


<commit_before>// Copyright 2015 Dorival Pedroso and Raul Durand. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fun

import "github.com/cpmech/gosl/chk"

// Lin implements a linear function w.r.t t
//  y = m * (t - ts)
type Lin struct {
	M  float64 // slope
	Ts float64 // shift
}

// set allocators database
func init() {
	allocators["lin"] = func() Func { return new(Lin) }
}

// Init initialises the function
func (o *Lin) Init(prms Prms) (err error) {
	e := prms.Connect(&o.M, "m")
	e += prms.Connect(&o.Ts, "ts")
	if e != "" {
		err = chk.Err("%v\n", e)
	}
	return
}

// F returns y = F(t, x)
func (o Lin) F(t float64, x []float64) float64 {
	return o.M * (t - o.Ts)
}

// G returns ∂y/∂t_cteX = G(t, x)
func (o Lin) G(t float64, x []float64) float64 {
	return o.M
}

// H returns ∂²y/∂t²_cteX = H(t, x)
func (o Lin) H(t float64, x []float64) float64 {
	return 0
}

// Grad returns ∇F = ∂y/∂x = Grad(t, x)
func (o Lin) Grad(v []float64, t float64, x []float64) {
	setvzero(v)
	return
}
<commit_msg>ts (time shift) is optional in f_lin<commit_after>// Copyright 2015 Dorival Pedroso and Raul Durand. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fun

import "github.com/cpmech/gosl/chk"

// Lin implements a linear function w.r.t t
//  y = m * (t - ts)
type Lin struct {
	M  float64 // slope
	Ts float64 // shift
}

// set allocators database
func init() {
	allocators["lin"] = func() Func { return new(Lin) }
}

// Init initialises the function
func (o *Lin) Init(prms Prms) (err error) {
	e := prms.Connect(&o.M, "m")
	prms.Connect(&o.Ts, "ts")
	if e != "" {
		err = chk.Err("%v\n", e)
	}
	return
}

// F returns y = F(t, x)
func (o Lin) F(t float64, x []float64) float64 {
	return o.M * (t - o.Ts)
}

// G returns ∂y/∂t_cteX = G(t, x)
func (o Lin) G(t float64, x []float64) float64 {
	return o.M
}

// H returns ∂²y/∂t²_cteX = H(t, x)
func (o Lin) H(t float64, x []float64) float64 {
	return 0
}

// Grad returns ∇F = ∂y/∂x = Grad(t, x)
func (o Lin) Grad(v []float64, t float64, x []float64) {
	setvzero(v)
	return
}
<|endoftext|>


<commit_before>package interfaces

import (
	"encoding/json"

	"github.com/AlekSi/pointer"
	pickle "github.com/hydrogen18/stalecucumber"
	"github.com/pkg/errors"
)

type Stacktrace struct {
	HasSystemFrames bool    `json:"hasSystemFrames"`
	FramesOmitted   *bool   `json:"framesOmitted"` // TODO type?
	Frames          []Frame `json:"frames"`
}

type Frame struct {
	ColumnNumber       *int                   `json:"colNo"`
	LineNumber         int                    `json:"lineNo"`
	InstructionOffset  *int                   `json:"instructionOffset"` // TODO type?
	InstructionAddress *string                `json:"instructionAddr"`   // TODO type?
	Symbol             *string                `json:"symbol"`            // TODO type?
	SymbolAddress      *string                `json:"symbolAddr"`        // TODO type?
	AbsolutePath       string                 `json:"absPath"`
	Module             string                 `json:"module"`
	Package            *string                `json:"package"`
	Platform           *string                `json:"platform"` // TODO type?
	Errors             *string                `json:"errors"`   // TODO type?
	InApp              bool                   `json:"inApp"`
	Filename           string                 `json:"filename"`
	Function           string                 `json:"function"`
	Context            FrameContext           `json:"context"`
	Variables          map[string]interface{} `json:"vars"`
}

type FrameContext []FrameContextLine

type FrameContextLine struct {
	LineNumber int
	Line       string
}

type stacktraceRecord struct {
	HasSystemFrames bool          `pickle:"has_system_frames"`
	FramesOmitted   *bool         `pickle:"frames_omitted"` // TODO type?
	Frames          []frameRecord `pickle:"frames"`
}

type frameRecord struct {
	ColumnNumber       *int                        `pickle:"colno"`
	LineNumber         int                         `pickle:"lineno"`
	InstructionAddress *string                     `pickle:"instruction_addr"` // TODO type?
	Symbol             *string                     `pickle:"symbol"`           // TODO type?
	SymbolAddress      *string                     `pickle:"symbol_addr"`      // TODO type?
	AbsolutePath       string                      `pickle:"abs_path"`
	Module             string                      `pickle:"module"`
	Package            *string                     `pickle:"package"`
	Platform           *string                     `pickle:"platform"` // TODO type?
	Errors             *string                     `pickle:"errors"`   // TODO type?
	InApp              bool                        `pickle:"in_app"`
	Filename           string                      `pickle:"filename"`
	Function           string                      `pickle:"function"`
	ContextLine        string                      `pickle:"context_line"`
	PreContext         []string                    `pickle:"pre_context"`
	PostContext        []string                    `pickle:"post_context"`
	Variables          map[interface{}]interface{} `pickle:"vars"`
}

func (contextLine FrameContextLine) MarshalJSON() ([]byte, error) {
	return json.Marshal([]interface{}{contextLine.LineNumber, contextLine.Line})
}

func (stacktrace *Stacktrace) UnmarshalRecord(nodeBlob interface{}) error {
	// TODO safe cast to map[interface{}]interface{}
	// TODO safe get from map using `stacktrace` alias key
	// TODO safe get from map using `sentry.interfaces.Stacktrace` canonical key
	record := stacktraceRecord{}
	if err := pickle.UnpackInto(&record).From(nodeBlob.(map[interface{}]interface{})["sentry.interfaces.Stacktrace"], nil); err != nil {
		return errors.Wrapf(err, "can not convert node blob to sentry.interfaces.Stacktrace")
	}
	for _, frameRecord := range record.Frames {
		frame := Frame{
			ColumnNumber:       frameRecord.ColumnNumber,
			LineNumber:         frameRecord.LineNumber,
			InstructionAddress: frameRecord.InstructionAddress,
			Symbol:             frameRecord.Symbol,
			SymbolAddress:      frameRecord.SymbolAddress,
			AbsolutePath:       frameRecord.AbsolutePath,
			Module:             frameRecord.Module,
			Package:            frameRecord.Package,
			Platform:           frameRecord.Platform,
			Errors:             frameRecord.Errors,
			InApp:              frameRecord.InApp,
			Filename:           frameRecord.Filename,
			Function:           frameRecord.Function,
		}
		//frame.InstructionAddress = padHexAddr(frameRecord.InstructionAddress, padAddr)
		//frame.SymbolAddress = padHexAddr(frameRecord.SymbolAddressRaw, padAddr)
		frame.Context = getFrameContext(
			frameRecord.LineNumber,
			frameRecord.ContextLine,
			frameRecord.PreContext,
			frameRecord.PostContext,
			frameRecord.Filename,
			frameRecord.Module,
		)
		frame.Variables = map[string]interface{}{}
		err := fillTypedVars(frameRecord.Variables, frame.Variables)
		if err != nil {
			return errors.Wrap(err, "failed to decode frame variables")
		}
		stacktrace.Frames = append(stacktrace.Frames, frame)
	}
	return nil
}

func getFrameContext(
	lineNumber int, contextLine string, preContext, postContext []string,
	filename, module string) FrameContext {
	if lineNumber == 0 {
		return nil
	}
	if contextLine == "" && !(preContext != nil || postContext != nil) {
		return nil
	}
	context := FrameContext{}
	startLineNumber := lineNumber - len(preContext)
	atLineNumber := startLineNumber
	for _, line := range preContext {
		context = append(context, FrameContextLine{LineNumber: atLineNumber, Line: line})
		atLineNumber++
	}
	if startLineNumber < 0 {
		startLineNumber = 0
	}
	context = append(context, FrameContextLine{LineNumber: atLineNumber, Line: contextLine})
	atLineNumber++
	for _, line := range postContext {
		context = append(context, FrameContextLine{LineNumber: atLineNumber, Line: line})
		atLineNumber++
	}
	return context
}

func fillTypedVars(sourceMap map[interface{}]interface{}, destMap map[string]interface{}) error {
	for nameBlob, valueBlob := range sourceMap {
		name := nameBlob.(string)
		switch value := valueBlob.(type) {
		case map[interface{}]interface{}:
			nestedMap := map[string]interface{}{}
			destMap[name] = nestedMap
			if err := fillTypedVars(value, nestedMap); err != nil {
				return err
			}
		case pickle.PickleNone:
			destMap[name] = nil
		case int64:
			destMap[name] = int(value)
		case []interface{}, string, bool:
			destMap[name] = value
		default:
			return errors.Errorf("unexpected type %T", value)
		}
	}
	return nil
}

// TODO toBool, toInt functions is copied between models and interfaces package
func toBool(value interface{}) bool {
	switch typedValue := value.(type) {
	case bool:
		return typedValue
	default:
		// TODO remove panic one all use-cases are checked
		panic(errors.Errorf("unexpected bool type %T", typedValue))
	}
}

func toInt(value interface{}) int {
	switch typedValue := value.(type) {
	case int64:
		return int(typedValue)
	case int:
		return typedValue
	default:
		// TODO remove panic one all use-cases are checked
		panic(errors.Errorf("unexpected int type %T", typedValue))
	}
}

func toIntPtr(value interface{}) *int {
	_, isPickleNone := value.(pickle.PickleNone)
	if value == nil || isPickleNone {
		return nil
	}
	return pointer.ToInt(toInt(value))
}

func toString(value interface{}) string {
	switch typedValue := value.(type) {
	case string:
		return typedValue
	default:
		// TODO remove panic one all use-cases are checked
		panic(errors.Errorf("unexpected string type %T", typedValue))
	}
}

func toStringPtr(value interface{}) *string {
	_, isPickleNone := value.(pickle.PickleNone)
	if value == nil || isPickleNone {
		return nil
	}
	return pointer.ToString(toString(value))
}

func toStringSlice(value interface{}) (rv []string) {
	if sliceValue, ok := value.([]interface{}); ok {
		for _, item := range sliceValue {
			rv = append(rv, toString(item))
		}
	}
	return
}

func toStringMapString(value interface{}) (rv map[string]string) {
	if mapValue, ok := value.(map[interface{}]interface{}); ok {
		rv = map[string]string{}
		for key, value := range mapValue {
			rv[toString(key)] = toString(value)
		}
	}
	return
}

func toStringMap(value interface{}) (rv map[string]interface{}) {
	if mapValue, ok := value.(map[interface{}]interface{}); ok {
		rv = map[string]interface{}{}
		for key, value := range mapValue {
			rv[toString(key)] = value
		}
	}
	return
}

func (stacktrace *Stacktrace) UnmarshalAPI(rawEvent map[string]interface{}) error {
	return nil
}
<commit_msg>Implement interfaces.Stacktrace.UnmarshalAPI<commit_after>package interfaces

import (
	"encoding/json"

	"github.com/AlekSi/pointer"
	pickle "github.com/hydrogen18/stalecucumber"
	"github.com/pkg/errors"
)

type Stacktrace struct {
	HasSystemFrames bool    `json:"hasSystemFrames"`
	FramesOmitted   *bool   `json:"framesOmitted"` // TODO type?
	Frames          []Frame `json:"frames"`
}

type Frame struct {
	ColumnNumber       *int                   `json:"colNo"`
	LineNumber         int                    `json:"lineNo"`
	InstructionOffset  *int                   `json:"instructionOffset"` // TODO type?
	InstructionAddress *string                `json:"instructionAddr"`   // TODO type?
	Symbol             *string                `json:"symbol"`            // TODO type?
	SymbolAddress      *string                `json:"symbolAddr"`        // TODO type?
	AbsolutePath       string                 `json:"absPath"`
	Module             string                 `json:"module"`
	Package            *string                `json:"package"`
	Platform           *string                `json:"platform"` // TODO type?
	Errors             *string                `json:"errors"`   // TODO type?
	InApp              bool                   `json:"inApp"`
	Filename           string                 `json:"filename"`
	Function           string                 `json:"function"`
	Context            FrameContext           `json:"context"`
	Variables          map[string]interface{} `json:"vars"`
}

type FrameContext []FrameContextLine

type FrameContextLine struct {
	LineNumber int
	Line       string
}

type stacktraceRecord struct {
	HasSystemFrames bool          `pickle:"has_system_frames"`
	FramesOmitted   *bool         `pickle:"frames_omitted"` // TODO type?
	Frames          []frameRecord `pickle:"frames"`
}

type frameRecord struct {
	ColumnNumber       *int                        `pickle:"colno"`
	LineNumber         int                         `pickle:"lineno"`
	InstructionAddress *string                     `pickle:"instruction_addr"` // TODO type?
	Symbol             *string                     `pickle:"symbol"`           // TODO type?
	SymbolAddress      *string                     `pickle:"symbol_addr"`      // TODO type?
	AbsolutePath       string                      `pickle:"abs_path"`
	Module             string                      `pickle:"module"`
	Package            *string                     `pickle:"package"`
	Platform           *string                     `pickle:"platform"` // TODO type?
	Errors             *string                     `pickle:"errors"`   // TODO type?
	InApp              bool                        `pickle:"in_app"`
	Filename           string                      `pickle:"filename"`
	Function           string                      `pickle:"function"`
	ContextLine        string                      `pickle:"context_line"`
	PreContext         []string                    `pickle:"pre_context"`
	PostContext        []string                    `pickle:"post_context"`
	Variables          map[interface{}]interface{} `pickle:"vars"`
}

func (contextLine FrameContextLine) MarshalJSON() ([]byte, error) {
	return json.Marshal([]interface{}{contextLine.LineNumber, contextLine.Line})
}

func (stacktrace *Stacktrace) UnmarshalRecord(nodeBlob interface{}) error {
	// TODO safe cast to map[interface{}]interface{}
	// TODO safe get from map using `stacktrace` alias key
	// TODO safe get from map using `sentry.interfaces.Stacktrace` canonical key
	record := stacktraceRecord{}
	if err := pickle.UnpackInto(&record).From(nodeBlob.(map[interface{}]interface{})["sentry.interfaces.Stacktrace"], nil); err != nil {
		return errors.Wrapf(err, "can not convert node blob to sentry.interfaces.Stacktrace")
	}
	for _, frameRecord := range record.Frames {
		frame := Frame{
			ColumnNumber:       frameRecord.ColumnNumber,
			LineNumber:         frameRecord.LineNumber,
			InstructionAddress: frameRecord.InstructionAddress,
			Symbol:             frameRecord.Symbol,
			SymbolAddress:      frameRecord.SymbolAddress,
			AbsolutePath:       frameRecord.AbsolutePath,
			Module:             frameRecord.Module,
			Package:            frameRecord.Package,
			Platform:           frameRecord.Platform,
			Errors:             frameRecord.Errors,
			InApp:              frameRecord.InApp,
			Filename:           frameRecord.Filename,
			Function:           frameRecord.Function,
		}
		//frame.InstructionAddress = padHexAddr(frameRecord.InstructionAddress, padAddr)
		//frame.SymbolAddress = padHexAddr(frameRecord.SymbolAddressRaw, padAddr)
		frame.Context = getFrameContext(
			frameRecord.LineNumber,
			frameRecord.ContextLine,
			frameRecord.PreContext,
			frameRecord.PostContext,
			frameRecord.Filename,
			frameRecord.Module,
		)
		frame.Variables = map[string]interface{}{}
		err := fillTypedVars(frameRecord.Variables, frame.Variables)
		if err != nil {
			return errors.Wrap(err, "failed to decode frame variables")
		}
		stacktrace.Frames = append(stacktrace.Frames, frame)
	}
	return nil
}

func getFrameContext(
	lineNumber int, contextLine string, preContext, postContext []string,
	filename, module string) FrameContext {
	if lineNumber == 0 {
		return nil
	}
	if contextLine == "" && !(preContext != nil || postContext != nil) {
		return nil
	}
	context := FrameContext{}
	startLineNumber := lineNumber - len(preContext)
	atLineNumber := startLineNumber
	for _, line := range preContext {
		context = append(context, FrameContextLine{LineNumber: atLineNumber, Line: line})
		atLineNumber++
	}
	if startLineNumber < 0 {
		startLineNumber = 0
	}
	context = append(context, FrameContextLine{LineNumber: atLineNumber, Line: contextLine})
	atLineNumber++
	for _, line := range postContext {
		context = append(context, FrameContextLine{LineNumber: atLineNumber, Line: line})
		atLineNumber++
	}
	return context
}

func fillTypedVars(sourceMap map[interface{}]interface{}, destMap map[string]interface{}) error {
	for nameBlob, valueBlob := range sourceMap {
		name := nameBlob.(string)
		switch value := valueBlob.(type) {
		case map[interface{}]interface{}:
			nestedMap := map[string]interface{}{}
			destMap[name] = nestedMap
			if err := fillTypedVars(value, nestedMap); err != nil {
				return err
			}
		case pickle.PickleNone:
			destMap[name] = nil
		case int64:
			destMap[name] = int(value)
		case []interface{}, string, bool:
			destMap[name] = value
		default:
			return errors.Errorf("unexpected type %T", value)
		}
	}
	return nil
}

// TODO toBool, toInt functions is copied between models and interfaces package
func toBool(value interface{}) bool {
	switch typedValue := value.(type) {
	case bool:
		return typedValue
	default:
		// TODO remove panic one all use-cases are checked
		panic(errors.Errorf("unexpected bool type %T", typedValue))
	}
}

func toInt(value interface{}) int {
	switch typedValue := value.(type) {
	case int64:
		return int(typedValue)
	case int:
		return typedValue
	default:
		// TODO remove panic one all use-cases are checked
		panic(errors.Errorf("unexpected int type %T", typedValue))
	}
}

func toIntPtr(value interface{}) *int {
	_, isPickleNone := value.(pickle.PickleNone)
	if value == nil || isPickleNone {
		return nil
	}
	return pointer.ToInt(toInt(value))
}

func toString(value interface{}) string {
	switch typedValue := value.(type) {
	case string:
		return typedValue
	default:
		// TODO remove panic one all use-cases are checked
		panic(errors.Errorf("unexpected string type %T", typedValue))
	}
}

func toStringPtr(value interface{}) *string {
	_, isPickleNone := value.(pickle.PickleNone)
	if value == nil || isPickleNone {
		return nil
	}
	return pointer.ToString(toString(value))
}

func toStringSlice(value interface{}) (rv []string) {
	if sliceValue, ok := value.([]interface{}); ok {
		for _, item := range sliceValue {
			rv = append(rv, toString(item))
		}
	}
	return
}

func toStringMapString(value interface{}) (rv map[string]string) {
	if mapValue, ok := value.(map[interface{}]interface{}); ok {
		rv = map[string]string{}
		for key, value := range mapValue {
			rv[toString(key)] = toString(value)
		}
	}
	return
}

func toStringMap(value interface{}) (rv map[string]interface{}) {
	if mapValue, ok := value.(map[interface{}]interface{}); ok {
		rv = map[string]interface{}{}
		for key, value := range mapValue {
			rv[toString(key)] = value
		}
	}
	return
}

// NOTE We are expecting here rawStacktrace instead of rawEvent
func (stacktrace *Stacktrace) UnmarshalAPI(rawStacktrace map[string]interface{}) error {
	rawFrames, ok := rawStacktrace["frames"].([]interface{})
	if !ok {
		return nil
	}
	for _, rawFrame := range rawFrames {
		frameMap := rawFrame.(map[string]interface{})
		frame := Frame{
			Filename:     frameMap["filename"].(string),
			Function:     frameMap["function"].(string),
			LineNumber:   int(frameMap["lineno"].(float64)),
			ColumnNumber: pointer.ToInt(int(frameMap["colno"].(float64))),
			InApp:        frameMap["in_app"].(bool),
		}
		stacktrace.Frames = append(stacktrace.Frames, frame)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
)

// Go Template Function Map here
var increment = 0

var templateFunctions = template.FuncMap{
	// simple additon function useful for counters
	"Add": func(a int, b int) int {
		return a + b
	},

	// strip function for removing characters from text
	"Strip": func(s string, rmv string) string {
		return strings.Replace(s, rmv, "", -1)
	},

	// Inc function returns an incremented value for each call.
	"Inc": func() string {
		increment = increment + 1
		return strconv.Itoa(increment)
	},

	// file function for reading text from a given file under the files folder
	"File": func(filename string) (string, error) {

		p := job.tplFiles[0]
		f := filepath.Join(filepath.Dir(p), "..", "files", filename)
		fmt.Println(f)
		b, err := ioutil.ReadFile(f)
		if err != nil {
			log.Fatal("Error reading the template file: ", err)
			return "", err
		}
		return string(b), nil
	},

	// Get get does an HTTP Get request of the given url and returns the output string
	"GET": func(url string) (string, error) {
		resp, err := Get(url)
		if err != nil {
			return "", err
		}

		return resp, nil
	},

	// S3Read reads content of file from s3 and returns string contents
	"S3Read": func(url string) (string, error) {
		resp, err := S3Read(url)
		if err != nil {
			return "", err
		}
		return resp, nil
	},
}
<commit_msg>adjust increment function<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
)

// Go Template Function Map here
var increment = 0

var templateFunctions = template.FuncMap{
	// simple additon function useful for counters
	"Add": func(a int, b int) int {
		return a + b
	},

	// strip function for removing characters from text
	"Strip": func(s string, rmv string) string {
		return strings.Replace(s, rmv, "", -1)
	},

	// Inc function returns an incremented value for each call.
	"Inc": func(reset bool) string {
		if reset {
			increment = 1
		}

		increment = increment + 1
		return strconv.Itoa(increment)
	},

	// file function for reading text from a given file under the files folder
	"File": func(filename string) (string, error) {

		p := job.tplFiles[0]
		f := filepath.Join(filepath.Dir(p), "..", "files", filename)
		fmt.Println(f)
		b, err := ioutil.ReadFile(f)
		if err != nil {
			log.Fatal("Error reading the template file: ", err)
			return "", err
		}
		return string(b), nil
	},

	// Get get does an HTTP Get request of the given url and returns the output string
	"GET": func(url string) (string, error) {
		resp, err := Get(url)
		if err != nil {
			return "", err
		}

		return resp, nil
	},

	// S3Read reads content of file from s3 and returns string contents
	"S3Read": func(url string) (string, error) {
		resp, err := S3Read(url)
		if err != nil {
			return "", err
		}
		return resp, nil
	},
}
<|endoftext|>


<commit_before>package gemini

import (
	"database/sql"
	"fmt"
	"reflect"
)

func (g *Gemini) Get(i interface{}, keys ...interface{}) error {
	// TODO(ttacon): really the key param should be variadic (for composite primary keys)
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)
	if !table.HasPrimaryKey() {
		return NoPrimaryKey
	}

	return g.getItFrom(i, keys, table)
}

func (g *Gemini) getItFrom(i interface{}, keys []interface{}, table *TableMap) error {
	// TODO(ttacon)
	primaryKeys := table.PrimaryKey()
	if len(primaryKeys) != len(keys) {
		return fmt.Errorf(
			"to use get, must provide correct number of primary keys (expected %d, got %d",
			len(primaryKeys),
			len(keys),
		)
	}

	queryString := "select "
	for i, field := range table.Fields {
		if i != 0 {
			queryString += ", "
		}
		queryString += field.columnName
	}

	queryString += " from " + table.TableName + " where "

	for i, key := range primaryKeys {
		if i != 0 {
			queryString += " and "
		}
		// TODO(ttacon): right now this doesn't deal with struct tag names nor
		// ensuring the value at key[i] is a decent value (not struct or pointer)
		// also, what if that field is a Struct, we need to know how to set the id
		// correctly
		queryString += fmt.Sprintf("%s = %v", key.Name, keys[i])
	}

	// this currently won't work for MongoDB
	db, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}

	rows, err := db.Db.Query(queryString)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Insert(i interface{}) error {
	if reflect.TypeOf(i).Kind() != reflect.Ptr {
		return fmt.Errorf("cannot insert non pointer type")
	}

	e := reflect.ValueOf(i).Elem()
	tableName := tableNameForStruct(e.Type())

	// TODO(ttacon): perhaps we should be smart and try to just insert if there is only one db
	// even if we don't have a mapping from table to db
	dbInfo, ok := g.TableToDatabaseInfo[tableName]
	if !ok {
		return fmt.Errorf("table %s is not specified to interact with any db", tableName)
	}
	db := dbInfo.Db

	tMap, ok := g.StructsMap[tableName]
	if !ok {
		return fmt.Errorf("table %s does not have a table map", tableName)
	}

	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(MongoDB{}) {
		return dbInfo.MongoSesh.DB(dbInfo.DbName).C(tableName).Insert(i)
	}

	// TODO(ttacon): make smart mapping of table name to db driver and dialect
	query, args := insertQueryAndArgs(e, tMap, dbInfo.Dialect)
	// TODO(ttacon): use result (the underscored place)?
	var autoIncrId int64
	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(PostgresDialect{}) {
		rows := db.QueryRow(query, args...)
		if tMap.autoIncrField != nil {
			err := rows.Scan(&autoIncrId)
			if err != nil {
				return err
			}
		}
	} else {
		result, err := db.Exec(query, args...)
		if err != nil {
			return err
		}
		if tMap.autoIncrField != nil {
			autoIncrId, err = result.LastInsertId()
			if err != nil {
				return err
			}
		}
	}

	if tMap.autoIncrField != nil {
		fieldVal := e.FieldByName(tMap.autoIncrField.Name)
		k := fieldVal.Kind()

		if (k == reflect.Int) || (k == reflect.Int16) || (k == reflect.Int32) || (k == reflect.Int64) {
			fieldVal.SetInt(autoIncrId)
		} else if (k == reflect.Uint16) || (k == reflect.Uint32) || (k == reflect.Uint64) {
			fieldVal.SetUint(uint64(autoIncrId))
		}
	}

	return nil
}

func (g *Gemini) Delete(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Update(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Select(i interface{}, query string, args ...interface{}) error {
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)

	dbi, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}
	rows, err := dbi.Db.Query(query, args...)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Exec(query string, args ...interface{}) (sql.Result, error) {
	if len(g.Dbs) == 1 {
		return g.Dbs[0].Exec(query, args...)
	}
	return nil, NoDbSpecified
}

func (g *Gemini) ExecWithInfo(query string, args ...interface{}, info *DbInfo) (sql.Result, error) {
	// TODO(ttacon): allow users to attach db name to DbInfo so they don't
	// have to hold onto the db info
	return info.Exec(query, args...)
}

func (g *Gemini) tableFor(i interface{}) *TableMap {
	var (
		tableName string
		val       = reflect.ValueOf(i)
	)

	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if v, ok := val.Type().FieldByName("TableInfo"); ok && v.Tag.Get("name") != "" {
		tableName = v.Tag.Get("name")
	} else {
		tableName = val.Type().Name()
	}

	// see if struct exists in table map
	if tMap, ok := g.StructsMap[tableName]; ok {
		return tMap
	}

	return TableMapFromStruct(i, tableName)
}
<commit_msg>move it<commit_after>package gemini

import (
	"database/sql"
	"fmt"
	"reflect"
)

func (g *Gemini) Get(i interface{}, keys ...interface{}) error {
	// TODO(ttacon): really the key param should be variadic (for composite primary keys)
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)
	if !table.HasPrimaryKey() {
		return NoPrimaryKey
	}

	return g.getItFrom(i, keys, table)
}

func (g *Gemini) getItFrom(i interface{}, keys []interface{}, table *TableMap) error {
	// TODO(ttacon)
	primaryKeys := table.PrimaryKey()
	if len(primaryKeys) != len(keys) {
		return fmt.Errorf(
			"to use get, must provide correct number of primary keys (expected %d, got %d",
			len(primaryKeys),
			len(keys),
		)
	}

	queryString := "select "
	for i, field := range table.Fields {
		if i != 0 {
			queryString += ", "
		}
		queryString += field.columnName
	}

	queryString += " from " + table.TableName + " where "

	for i, key := range primaryKeys {
		if i != 0 {
			queryString += " and "
		}
		// TODO(ttacon): right now this doesn't deal with struct tag names nor
		// ensuring the value at key[i] is a decent value (not struct or pointer)
		// also, what if that field is a Struct, we need to know how to set the id
		// correctly
		queryString += fmt.Sprintf("%s = %v", key.Name, keys[i])
	}

	// this currently won't work for MongoDB
	db, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}

	rows, err := db.Db.Query(queryString)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if reflect.TypeOf(i).Kind() == reflect.Slice {

		for rows.Next() {
			if rows.Err() != nil {
				return rows.Err()
			}

			v := reflect.ValueOf(i)
			if v.Kind() == reflect.Ptr {
				v = v.Elem()
			}

			target := make([]interface{}, len(cols))
			for i, col := range cols {
				// TODO(ttacon): go through evern column here
				// TODO(ttacon): need to make sure this is all safe
				f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
				target[i] = f.Addr().Interface()
			}
		}
	}
	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Insert(i interface{}) error {
	if reflect.TypeOf(i).Kind() != reflect.Ptr {
		return fmt.Errorf("cannot insert non pointer type")
	}

	e := reflect.ValueOf(i).Elem()
	tableName := tableNameForStruct(e.Type())

	// TODO(ttacon): perhaps we should be smart and try to just insert if there is only one db
	// even if we don't have a mapping from table to db
	dbInfo, ok := g.TableToDatabaseInfo[tableName]
	if !ok {
		return fmt.Errorf("table %s is not specified to interact with any db", tableName)
	}
	db := dbInfo.Db

	tMap, ok := g.StructsMap[tableName]
	if !ok {
		return fmt.Errorf("table %s does not have a table map", tableName)
	}

	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(MongoDB{}) {
		return dbInfo.MongoSesh.DB(dbInfo.DbName).C(tableName).Insert(i)
	}

	// TODO(ttacon): make smart mapping of table name to db driver and dialect
	query, args := insertQueryAndArgs(e, tMap, dbInfo.Dialect)
	// TODO(ttacon): use result (the underscored place)?
	var autoIncrId int64
	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(PostgresDialect{}) {
		rows := db.QueryRow(query, args...)
		if tMap.autoIncrField != nil {
			err := rows.Scan(&autoIncrId)
			if err != nil {
				return err
			}
		}
	} else {
		result, err := db.Exec(query, args...)
		if err != nil {
			return err
		}
		if tMap.autoIncrField != nil {
			autoIncrId, err = result.LastInsertId()
			if err != nil {
				return err
			}
		}
	}

	if tMap.autoIncrField != nil {
		fieldVal := e.FieldByName(tMap.autoIncrField.Name)
		k := fieldVal.Kind()

		if (k == reflect.Int) || (k == reflect.Int16) || (k == reflect.Int32) || (k == reflect.Int64) {
			fieldVal.SetInt(autoIncrId)
		} else if (k == reflect.Uint16) || (k == reflect.Uint32) || (k == reflect.Uint64) {
			fieldVal.SetUint(uint64(autoIncrId))
		}
	}

	return nil
}

func (g *Gemini) Delete(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Update(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Select(i interface{}, query string, args ...interface{}) error {
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)

	dbi, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}
	rows, err := dbi.Db.Query(query, args...)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Exec(query string, args ...interface{}) (sql.Result, error) {
	if len(g.Dbs) == 1 {
		return g.Dbs[0].Exec(query, args...)
	}
	return nil, NoDbSpecified
}

func (g *Gemini) ExecWithInfo(query string, info *DbInfo, args ...interface{}) (sql.Result, error) {
	// TODO(ttacon): allow users to attach db name to DbInfo so they don't
	// have to hold onto the db info
	return info.Db.Exec(query, args...)
}

func (g *Gemini) tableFor(i interface{}) *TableMap {
	var (
		tableName string
		val       = reflect.ValueOf(i)
	)

	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if v, ok := val.Type().FieldByName("TableInfo"); ok && v.Tag.Get("name") != "" {
		tableName = v.Tag.Get("name")
	} else {
		tableName = val.Type().Name()
	}

	// see if struct exists in table map
	if tMap, ok := g.StructsMap[tableName]; ok {
		return tMap
	}

	return TableMapFromStruct(i, tableName)
}
<|endoftext|>


<commit_before>package oci8_test

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/mattn/go-oci8"
)

func Example_sqlSelect() {
	// Example shows how to do a basic select

	// For testing, check if database tests are disabled
	if oci8.TestDisableDatabase {
		fmt.Println(1)
		return
	}

	oci8.OCI8Driver.Logger = log.New(os.Stderr, "oci8 ", log.Ldate|log.Ltime|log.LUTC|log.Llongfile)

	var openString string
	// [username/[password]@]host[:port][/instance_name][?param1=value1&...&paramN=valueN]
	if len(oci8.TestUsername) > 0 {
		if len(oci8.TestPassword) > 0 {
			openString = oci8.TestUsername + "/" + oci8.TestPassword + "@"
		} else {
			openString = oci8.TestUsername + "@"
		}
	}
	openString += oci8.TestHostValid

	// A normal simple Open to localhost would look like:
	// db, err := sql.Open("oci8", "127.0.0.1")
	// For testing, need to use additional variables
	db, err := sql.Open("oci8", openString)
	if err != nil {
		fmt.Printf("Open error is not nil: %v", err)
		return
	}
	if db == nil {
		fmt.Println("db is nil")
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	defer cancel()
	rows, err := db.QueryContext(ctx, "select 1 from dual")
	if err != nil {
		fmt.Println("QueryContext error is not nil:", err)
		return
	}
	if !rows.Next() {
		fmt.Println("no Next rows")
		return
	}

	dest := make([]interface{}, 1)
	destPointer := make([]interface{}, 1)
	destPointer[0] = &dest[0]
	err = rows.Scan(destPointer...)
	if err != nil {
		fmt.Println("Scan error is not nil:", err)
		return
	}

	if len(dest) != 1 {
		fmt.Println("len dest != 1")
		return
	}
	data, ok := dest[0].(float64)
	if !ok {
		fmt.Println("dest type not float64")
		return
	}
	if data != 1 {
		fmt.Println("data not equal to 1")
		return
	}

	if rows.Next() {
		fmt.Println("has Next rows")
		return
	}

	err = rows.Err()
	if err != nil {
		fmt.Println("Err error is not nil:", err)
		return
	}
	err = rows.Close()
	if err != nil {
		fmt.Println("Close error is not nil:", err)
		return
	}
	cancel()

	err = db.Close()
	if err != nil {
		fmt.Println("Close error is not nil:", err)
		return
	}

	fmt.Println(data)

	// output: 1
}

func Example_sqlFunction() {
	// Example shows how to do a function call with binds

	// For testing, check if database tests are disabled
	if oci8.TestDisableDatabase {
		fmt.Println(3)
		return
	}

	oci8.OCI8Driver.Logger = log.New(os.Stderr, "oci8 ", log.Ldate|log.Ltime|log.LUTC|log.Llongfile)

	var openString string
	// [username/[password]@]host[:port][/instance_name][?param1=value1&...&paramN=valueN]
	if len(oci8.TestUsername) > 0 {
		if len(oci8.TestPassword) > 0 {
			openString = oci8.TestUsername + "/" + oci8.TestPassword + "@"
		} else {
			openString = oci8.TestUsername + "@"
		}
	}
	openString += oci8.TestHostValid

	// A normal simple Open to localhost would look like:
	// db, err := sql.Open("oci8", "127.0.0.1")
	// For testing, need to use additional variables
	db, err := sql.Open("oci8", openString)
	if err != nil {
		fmt.Printf("Open error is not nil: %v", err)
		return
	}
	if db == nil {
		fmt.Println("db is nil")
		return
	}

	number := int64(2)
	query := `
declare
	function ADD_ONE(p_number INTEGER) return INTEGER as
	begin
		return p_number + 1;
	end ADD_ONE;
begin
	:num1 := ADD_ONE(:num1);
end;`

	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	defer cancel()
	_, err = db.ExecContext(ctx, query, sql.Out{Dest: &number, In: true})
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	if number != 3 {
		fmt.Println("number != 3")
		return
	}

	fmt.Println(number)

	// output: 3
}

func Example_sqlInsert() {
	// Example shows how to do a single insert

	// For testing, check if database tests are disabled
	if oci8.TestDisableDatabase || oci8.TestDisableDestructive {
		fmt.Println(1)
		return
	}

	oci8.OCI8Driver.Logger = log.New(os.Stderr, "oci8 ", log.Ldate|log.Ltime|log.LUTC|log.Llongfile)

	var openString string
	// [username/[password]@]host[:port][/instance_name][?param1=value1&...&paramN=valueN]
	if len(oci8.TestUsername) > 0 {
		if len(oci8.TestPassword) > 0 {
			openString = oci8.TestUsername + "/" + oci8.TestPassword + "@"
		} else {
			openString = oci8.TestUsername + "@"
		}
	}
	openString += oci8.TestHostValid

	// A normal simple Open to localhost would look like:
	// db, err := sql.Open("oci8", "127.0.0.1")
	// For testing, need to use additional variables
	db, err := sql.Open("oci8", openString)
	if err != nil {
		fmt.Printf("Open error is not nil: %v", err)
		return
	}
	if db == nil {
		fmt.Println("db is nil")
		return
	}

	// create table
	tableName := "E_INSERT_" + oci8.TestTimeString
	query := "create table " + tableName + " ( A INTEGER )"
	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	_, err = db.ExecContext(ctx, query)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	// insert row
	var result sql.Result
	query = "insert into " + tableName + " ( A ) values (:1)"
	ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
	result, err = db.ExecContext(ctx, query, 1)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	// can see number of RowsAffected if wanted
	var rowsAffected int64
	rowsAffected, err = result.RowsAffected()
	if err != nil {
		fmt.Println("RowsAffected error is not nil:", err)
		return
	}

	// drop table
	query = "drop table " + tableName
	ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
	_, err = db.ExecContext(ctx, query)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	fmt.Println(rowsAffected)

	// output: 1
}
<commit_msg>Added Example_sqlManyInserts<commit_after>package oci8_test

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/mattn/go-oci8"
)

func Example_sqlSelect() {
	// Example shows how to do a basic select

	// For testing, check if database tests are disabled
	if oci8.TestDisableDatabase {
		fmt.Println(1)
		return
	}

	oci8.OCI8Driver.Logger = log.New(os.Stderr, "oci8 ", log.Ldate|log.Ltime|log.LUTC|log.Llongfile)

	var openString string
	// [username/[password]@]host[:port][/instance_name][?param1=value1&...&paramN=valueN]
	if len(oci8.TestUsername) > 0 {
		if len(oci8.TestPassword) > 0 {
			openString = oci8.TestUsername + "/" + oci8.TestPassword + "@"
		} else {
			openString = oci8.TestUsername + "@"
		}
	}
	openString += oci8.TestHostValid

	// A normal simple Open to localhost would look like:
	// db, err := sql.Open("oci8", "127.0.0.1")
	// For testing, need to use additional variables
	db, err := sql.Open("oci8", openString)
	if err != nil {
		fmt.Printf("Open error is not nil: %v", err)
		return
	}
	if db == nil {
		fmt.Println("db is nil")
		return
	}

	// defer close database
	defer func() {
		err = db.Close()
		if err != nil {
			fmt.Println("Close error is not nil:", err)
		}
	}()

	var rows *sql.Rows
	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	defer cancel()
	rows, err = db.QueryContext(ctx, "select 1 from dual")
	if err != nil {
		fmt.Println("QueryContext error is not nil:", err)
		return
	}
	if !rows.Next() {
		fmt.Println("no Next rows")
		return
	}

	dest := make([]interface{}, 1)
	destPointer := make([]interface{}, 1)
	destPointer[0] = &dest[0]
	err = rows.Scan(destPointer...)
	if err != nil {
		fmt.Println("Scan error is not nil:", err)
		return
	}

	if len(dest) != 1 {
		fmt.Println("len dest != 1")
		return
	}
	data, ok := dest[0].(float64)
	if !ok {
		fmt.Println("dest type not float64")
		return
	}
	if data != 1 {
		fmt.Println("data not equal to 1")
		return
	}

	if rows.Next() {
		fmt.Println("has Next rows")
		return
	}

	err = rows.Err()
	if err != nil {
		fmt.Println("Err error is not nil:", err)
		return
	}
	err = rows.Close()
	if err != nil {
		fmt.Println("Close error is not nil:", err)
		return
	}

	fmt.Println(data)

	// output: 1
}

func Example_sqlFunction() {
	// Example shows how to do a function call with binds

	// For testing, check if database tests are disabled
	if oci8.TestDisableDatabase {
		fmt.Println(3)
		return
	}

	oci8.OCI8Driver.Logger = log.New(os.Stderr, "oci8 ", log.Ldate|log.Ltime|log.LUTC|log.Llongfile)

	var openString string
	// [username/[password]@]host[:port][/instance_name][?param1=value1&...&paramN=valueN]
	if len(oci8.TestUsername) > 0 {
		if len(oci8.TestPassword) > 0 {
			openString = oci8.TestUsername + "/" + oci8.TestPassword + "@"
		} else {
			openString = oci8.TestUsername + "@"
		}
	}
	openString += oci8.TestHostValid

	// A normal simple Open to localhost would look like:
	// db, err := sql.Open("oci8", "127.0.0.1")
	// For testing, need to use additional variables
	db, err := sql.Open("oci8", openString)
	if err != nil {
		fmt.Printf("Open error is not nil: %v", err)
		return
	}
	if db == nil {
		fmt.Println("db is nil")
		return
	}

	// defer close database
	defer func() {
		err = db.Close()
		if err != nil {
			fmt.Println("Close error is not nil:", err)
		}
	}()

	number := int64(2)
	query := `
declare
	function ADD_ONE(p_number INTEGER) return INTEGER as
	begin
		return p_number + 1;
	end ADD_ONE;
begin
	:num1 := ADD_ONE(:num1);
end;`

	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	_, err = db.ExecContext(ctx, query, sql.Out{Dest: &number, In: true})
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	if number != 3 {
		fmt.Println("number != 3")
		return
	}

	fmt.Println(number)

	// output: 3
}

func Example_sqlInsert() {
	// Example shows how to do a single insert

	// For testing, check if database tests are disabled
	if oci8.TestDisableDatabase || oci8.TestDisableDestructive {
		fmt.Println(1)
		return
	}

	oci8.OCI8Driver.Logger = log.New(os.Stderr, "oci8 ", log.Ldate|log.Ltime|log.LUTC|log.Llongfile)

	var openString string
	// [username/[password]@]host[:port][/instance_name][?param1=value1&...&paramN=valueN]
	if len(oci8.TestUsername) > 0 {
		if len(oci8.TestPassword) > 0 {
			openString = oci8.TestUsername + "/" + oci8.TestPassword + "@"
		} else {
			openString = oci8.TestUsername + "@"
		}
	}
	openString += oci8.TestHostValid

	// A normal simple Open to localhost would look like:
	// db, err := sql.Open("oci8", "127.0.0.1")
	// For testing, need to use additional variables
	db, err := sql.Open("oci8", openString)
	if err != nil {
		fmt.Printf("Open error is not nil: %v", err)
		return
	}
	if db == nil {
		fmt.Println("db is nil")
		return
	}

	// defer close database
	defer func() {
		err = db.Close()
		if err != nil {
			fmt.Println("Close error is not nil:", err)
		}
	}()

	// create table
	tableName := "E_INSERT_" + oci8.TestTimeString
	query := "create table " + tableName + " ( A INTEGER )"
	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	_, err = db.ExecContext(ctx, query)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	// insert row
	var result sql.Result
	query = "insert into " + tableName + " ( A ) values (:1)"
	ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
	result, err = db.ExecContext(ctx, query, 1)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	// can see number of RowsAffected if wanted
	var rowsAffected int64
	rowsAffected, err = result.RowsAffected()
	if err != nil {
		fmt.Println("RowsAffected error is not nil:", err)
		return
	}

	// drop table
	query = "drop table " + tableName
	ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
	_, err = db.ExecContext(ctx, query)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	err = db.Close()
	if err != nil {
		fmt.Println("Close error is not nil:", err)
		return
	}

	fmt.Println(rowsAffected)

	// output: 1
}

func Example_sqlManyInserts() {
	// Example shows how to do a many inserts

	// For testing, check if database tests are disabled
	if oci8.TestDisableDatabase || oci8.TestDisableDestructive {
		fmt.Println(3)
		return
	}

	oci8.OCI8Driver.Logger = log.New(os.Stderr, "oci8 ", log.Ldate|log.Ltime|log.LUTC|log.Llongfile)

	var openString string
	// [username/[password]@]host[:port][/instance_name][?param1=value1&...&paramN=valueN]
	if len(oci8.TestUsername) > 0 {
		if len(oci8.TestPassword) > 0 {
			openString = oci8.TestUsername + "/" + oci8.TestPassword + "@"
		} else {
			openString = oci8.TestUsername + "@"
		}
	}
	openString += oci8.TestHostValid

	// A normal simple Open to localhost would look like:
	// db, err := sql.Open("oci8", "127.0.0.1")
	// For testing, need to use additional variables
	db, err := sql.Open("oci8", openString)
	if err != nil {
		fmt.Printf("Open error is not nil: %v", err)
		return
	}
	if db == nil {
		fmt.Println("db is nil")
		return
	}

	// defer close database
	defer func() {
		err = db.Close()
		if err != nil {
			fmt.Println("Close error is not nil:", err)
		}
	}()

	// create table
	tableName := "E_MANY_INSERT_" + oci8.TestTimeString
	query := "create table " + tableName + " ( A INTEGER )"
	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	_, err = db.ExecContext(ctx, query)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	// prepare insert query statement
	var stmt *sql.Stmt
	query = "insert into " + tableName + " ( A ) values (:1)"
	ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
	stmt, err = db.PrepareContext(ctx, query)
	cancel()
	if err != nil {
		fmt.Println("PrepareContext error is not nil:", err)
		return
	}

	// insert 3 rows
	for i := 0; i < 3; i++ {
		ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
		_, err = stmt.ExecContext(ctx, i)
		cancel()
		if err != nil {
			stmt.Close()
			fmt.Println("ExecContext error is not nil:", err)
			return
		}
	}

	// close insert query statement
	err = stmt.Close()
	if err != nil {
		fmt.Println("Close error is not nil:", err)
		return
	}

	// select count/number of rows
	var rows *sql.Rows
	query = "select count(1) from " + tableName
	ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
	defer cancel()
	rows, err = db.QueryContext(ctx, query)
	if err != nil {
		fmt.Println("QueryContext error is not nil:", err)
		return
	}
	if !rows.Next() {
		fmt.Println("no Next rows")
		return
	}

	var count int64
	err = rows.Scan(&count)
	if err != nil {
		fmt.Println("Scan error is not nil:", err)
		return
	}

	if count != 3 {
		fmt.Println("count not equal to 3")
		return
	}

	if rows.Next() {
		fmt.Println("has Next rows")
		return
	}

	err = rows.Err()
	if err != nil {
		fmt.Println("Err error is not nil:", err)
		return
	}
	err = rows.Close()
	if err != nil {
		fmt.Println("Close error is not nil:", err)
		return
	}

	// drop table
	query = "drop table " + tableName
	ctx, cancel = context.WithTimeout(context.Background(), 55*time.Second)
	_, err = db.ExecContext(ctx, query)
	cancel()
	if err != nil {
		fmt.Println("ExecContext error is not nil:", err)
		return
	}

	fmt.Println(count)

	// output: 3
}
<|endoftext|>


<commit_before>package proto

import (
	"bufio"
	"fmt"
	"io"

	"github.com/go-redis/redis/v7/internal/util"
)

const (
	ErrorReply  = '-'
	StatusReply = '+'
	IntReply    = ':'
	StringReply = '$'
	ArrayReply  = '*'
)

//------------------------------------------------------------------------------

const Nil = RedisError("redis: nil")

type RedisError string

func (e RedisError) Error() string { return string(e) }

//------------------------------------------------------------------------------

type MultiBulkParse func(*Reader, int64) (interface{}, error)

type Reader struct {
	rd   *bufio.Reader
	_buf []byte
}

func NewReader(rd io.Reader) *Reader {
	return &Reader{
		rd:   bufio.NewReader(rd),
		_buf: make([]byte, 64),
	}
}

func (r *Reader) Buffered() int {
	return r.rd.Buffered()
}

func (r *Reader) Reset(rd io.Reader) {
	r.rd.Reset(rd)
}

func (r *Reader) ReadLine() ([]byte, error) {
	line, isPrefix, err := r.rd.ReadLine()
	if err != nil {
		return nil, err
	}
	if isPrefix {
		return nil, bufio.ErrBufferFull
	}
	if len(line) == 0 {
		return nil, fmt.Errorf("redis: reply is empty")
	}
	if isNilReply(line) {
		return nil, Nil
	}
	return line, nil
}

func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}

	switch line[0] {
	case ErrorReply:
		return nil, ParseErrorReply(line)
	case StatusReply:
		return string(line[1:]), nil
	case IntReply:
		return util.ParseInt(line[1:], 10, 64)
	case StringReply:
		return r.readStringReply(line)
	case ArrayReply:
		n, err := parseArrayLen(line)
		if err != nil {
			return nil, err
		}
		if m == nil {
			err := fmt.Errorf("redis: got %.100q, but multi bulk parser is nil", line)
			return nil, err
		}
		return m(r, n)
	}
	return nil, fmt.Errorf("redis: can't parse %.100q", line)
}

func (r *Reader) ReadIntReply() (int64, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case ErrorReply:
		return 0, ParseErrorReply(line)
	case IntReply:
		return util.ParseInt(line[1:], 10, 64)
	default:
		return 0, fmt.Errorf("redis: can't parse int reply: %.100q", line)
	}
}

func (r *Reader) ReadString() (string, error) {
	line, err := r.ReadLine()
	if err != nil {
		return "", err
	}
	switch line[0] {
	case ErrorReply:
		return "", ParseErrorReply(line)
	case StringReply:
		return r.readStringReply(line)
	case StatusReply:
		return string(line[1:]), nil
	case IntReply:
		return string(line[1:]), nil
	default:
		return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
	}
}

func (r *Reader) readStringReply(line []byte) (string, error) {
	if isNilReply(line) {
		return "", Nil
	}

	replyLen, err := util.Atoi(line[1:])
	if err != nil {
		return "", err
	}

	b := make([]byte, replyLen+2)
	_, err = io.ReadFull(r.rd, b)
	if err != nil {
		return "", err
	}

	return util.BytesToString(b[:replyLen]), nil
}

func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}
	switch line[0] {
	case ErrorReply:
		return nil, ParseErrorReply(line)
	case ArrayReply:
		n, err := parseArrayLen(line)
		if err != nil {
			return nil, err
		}
		return m(r, n)
	default:
		return nil, fmt.Errorf("redis: can't parse array reply: %.100q", line)
	}
}

func (r *Reader) ReadArrayLen() (int64, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case ErrorReply:
		return 0, ParseErrorReply(line)
	case ArrayReply:
		return parseArrayLen(line)
	default:
		return 0, fmt.Errorf("redis: can't parse array reply: %.100q", line)
	}
}

func (r *Reader) ReadScanReply() ([]string, uint64, error) {
	n, err := r.ReadArrayLen()
	if err != nil {
		return nil, 0, err
	}
	if n != 2 {
		return nil, 0, fmt.Errorf("redis: got %d elements in scan reply, expected 2", n)
	}

	cursor, err := r.ReadUint()
	if err != nil {
		return nil, 0, err
	}

	n, err = r.ReadArrayLen()
	if err != nil {
		return nil, 0, err
	}

	keys := make([]string, n)
	for i := int64(0); i < n; i++ {
		key, err := r.ReadString()
		if err != nil {
			return nil, 0, err
		}
		keys[i] = key
	}

	return keys, cursor, err
}

func (r *Reader) ReadInt() (int64, error) {
	b, err := r.readTmpBytesReply()
	if err != nil {
		return 0, err
	}
	return util.ParseInt(b, 10, 64)
}

func (r *Reader) ReadUint() (uint64, error) {
	b, err := r.readTmpBytesReply()
	if err != nil {
		return 0, err
	}
	return util.ParseUint(b, 10, 64)
}

func (r *Reader) ReadFloatReply() (float64, error) {
	b, err := r.readTmpBytesReply()
	if err != nil {
		return 0, err
	}
	return util.ParseFloat(b, 64)
}

func (r *Reader) readTmpBytesReply() ([]byte, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}
	switch line[0] {
	case ErrorReply:
		return nil, ParseErrorReply(line)
	case StringReply:
		return r._readTmpBytesReply(line)
	case StatusReply:
		return line[1:], nil
	default:
		return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line)
	}
}

func (r *Reader) _readTmpBytesReply(line []byte) ([]byte, error) {
	if isNilReply(line) {
		return nil, Nil
	}

	replyLen, err := util.Atoi(line[1:])
	if err != nil {
		return nil, err
	}

	buf := r.buf(replyLen + 2)
	_, err = io.ReadFull(r.rd, buf)
	if err != nil {
		return nil, err
	}

	return buf[:replyLen], nil
}

func (r *Reader) buf(n int) []byte {
	if d := n - cap(r._buf); d > 0 {
		r._buf = append(r._buf, make([]byte, d)...)
	}
	return r._buf[:n]
}

func isNilReply(b []byte) bool {
	return len(b) == 3 &&
		(b[0] == StringReply || b[0] == ArrayReply) &&
		b[1] == '-' && b[2] == '1'
}

func ParseErrorReply(line []byte) error {
	return RedisError(string(line[1:]))
}

func parseArrayLen(line []byte) (int64, error) {
	if isNilReply(line) {
		return 0, Nil
	}
	return util.ParseInt(line[1:], 10, 64)
}
<commit_msg>internal/proto: use strict ReadLine<commit_after>package proto

import (
	"bufio"
	"fmt"
	"io"

	"github.com/go-redis/redis/v7/internal/util"
)

const (
	ErrorReply  = '-'
	StatusReply = '+'
	IntReply    = ':'
	StringReply = '$'
	ArrayReply  = '*'
)

//------------------------------------------------------------------------------

const Nil = RedisError("redis: nil")

type RedisError string

func (e RedisError) Error() string { return string(e) }

//------------------------------------------------------------------------------

type MultiBulkParse func(*Reader, int64) (interface{}, error)

type Reader struct {
	rd   *bufio.Reader
	_buf []byte
}

func NewReader(rd io.Reader) *Reader {
	return &Reader{
		rd:   bufio.NewReader(rd),
		_buf: make([]byte, 64),
	}
}

func (r *Reader) Buffered() int {
	return r.rd.Buffered()
}

func (r *Reader) Peek(n int) ([]byte, error) {
	return r.rd.Peek(n)
}

func (r *Reader) Reset(rd io.Reader) {
	r.rd.Reset(rd)
}

func (r *Reader) ReadLine() ([]byte, error) {
	line, err := r.readLine()
	if err != nil {
		return nil, err
	}
	if isNilReply(line) {
		return nil, Nil
	}
	return line, nil
}

// readLine that returns an error if:
//   - there is a pending read error;
//   - or line does not end with \r\n.
func (r *Reader) readLine() ([]byte, error) {
	b, err := r.rd.ReadSlice('\n')
	if err != nil {
		return nil, err
	}
	if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' {
		return nil, fmt.Errorf("redis: invalid reply: %q", b)
	}
	b = b[:len(b)-2]
	return b, nil
}

func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}

	switch line[0] {
	case ErrorReply:
		return nil, ParseErrorReply(line)
	case StatusReply:
		return string(line[1:]), nil
	case IntReply:
		return util.ParseInt(line[1:], 10, 64)
	case StringReply:
		return r.readStringReply(line)
	case ArrayReply:
		n, err := parseArrayLen(line)
		if err != nil {
			return nil, err
		}
		if m == nil {
			err := fmt.Errorf("redis: got %.100q, but multi bulk parser is nil", line)
			return nil, err
		}
		return m(r, n)
	}
	return nil, fmt.Errorf("redis: can't parse %.100q", line)
}

func (r *Reader) ReadIntReply() (int64, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case ErrorReply:
		return 0, ParseErrorReply(line)
	case IntReply:
		return util.ParseInt(line[1:], 10, 64)
	default:
		return 0, fmt.Errorf("redis: can't parse int reply: %.100q", line)
	}
}

func (r *Reader) ReadString() (string, error) {
	line, err := r.ReadLine()
	if err != nil {
		return "", err
	}
	switch line[0] {
	case ErrorReply:
		return "", ParseErrorReply(line)
	case StringReply:
		return r.readStringReply(line)
	case StatusReply:
		return string(line[1:]), nil
	case IntReply:
		return string(line[1:]), nil
	default:
		return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
	}
}

func (r *Reader) readStringReply(line []byte) (string, error) {
	if isNilReply(line) {
		return "", Nil
	}

	replyLen, err := util.Atoi(line[1:])
	if err != nil {
		return "", err
	}

	b := make([]byte, replyLen+2)
	_, err = io.ReadFull(r.rd, b)
	if err != nil {
		return "", err
	}

	return util.BytesToString(b[:replyLen]), nil
}

func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}
	switch line[0] {
	case ErrorReply:
		return nil, ParseErrorReply(line)
	case ArrayReply:
		n, err := parseArrayLen(line)
		if err != nil {
			return nil, err
		}
		return m(r, n)
	default:
		return nil, fmt.Errorf("redis: can't parse array reply: %.100q", line)
	}
}

func (r *Reader) ReadArrayLen() (int64, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case ErrorReply:
		return 0, ParseErrorReply(line)
	case ArrayReply:
		return parseArrayLen(line)
	default:
		return 0, fmt.Errorf("redis: can't parse array reply: %.100q", line)
	}
}

func (r *Reader) ReadScanReply() ([]string, uint64, error) {
	n, err := r.ReadArrayLen()
	if err != nil {
		return nil, 0, err
	}
	if n != 2 {
		return nil, 0, fmt.Errorf("redis: got %d elements in scan reply, expected 2", n)
	}

	cursor, err := r.ReadUint()
	if err != nil {
		return nil, 0, err
	}

	n, err = r.ReadArrayLen()
	if err != nil {
		return nil, 0, err
	}

	keys := make([]string, n)
	for i := int64(0); i < n; i++ {
		key, err := r.ReadString()
		if err != nil {
			return nil, 0, err
		}
		keys[i] = key
	}

	return keys, cursor, err
}

func (r *Reader) ReadInt() (int64, error) {
	b, err := r.readTmpBytesReply()
	if err != nil {
		return 0, err
	}
	return util.ParseInt(b, 10, 64)
}

func (r *Reader) ReadUint() (uint64, error) {
	b, err := r.readTmpBytesReply()
	if err != nil {
		return 0, err
	}
	return util.ParseUint(b, 10, 64)
}

func (r *Reader) ReadFloatReply() (float64, error) {
	b, err := r.readTmpBytesReply()
	if err != nil {
		return 0, err
	}
	return util.ParseFloat(b, 64)
}

func (r *Reader) readTmpBytesReply() ([]byte, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}
	switch line[0] {
	case ErrorReply:
		return nil, ParseErrorReply(line)
	case StringReply:
		return r._readTmpBytesReply(line)
	case StatusReply:
		return line[1:], nil
	default:
		return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line)
	}
}

func (r *Reader) _readTmpBytesReply(line []byte) ([]byte, error) {
	if isNilReply(line) {
		return nil, Nil
	}

	replyLen, err := util.Atoi(line[1:])
	if err != nil {
		return nil, err
	}

	buf := r.buf(replyLen + 2)
	_, err = io.ReadFull(r.rd, buf)
	if err != nil {
		return nil, err
	}

	return buf[:replyLen], nil
}

func (r *Reader) buf(n int) []byte {
	if n <= cap(r._buf) {
		return r._buf[:n]
	}
	d := n - cap(r._buf)
	r._buf = append(r._buf, make([]byte, d)...)
	return r._buf
}

func isNilReply(b []byte) bool {
	return len(b) == 3 &&
		(b[0] == StringReply || b[0] == ArrayReply) &&
		b[1] == '-' && b[2] == '1'
}

func ParseErrorReply(line []byte) error {
	return RedisError(string(line[1:]))
}

func parseArrayLen(line []byte) (int64, error) {
	if isNilReply(line) {
		return 0, Nil
	}
	return util.ParseInt(line[1:], 10, 64)
}
<|endoftext|>


<commit_before>package gemini

import (
	"fmt"
	"reflect"
)

func (g *Gemini) Get(i interface{}, keys ...interface{}) error {
	// TODO(ttacon): really the key param should be variadic (for composite primary keys)
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)
	if !table.HasPrimaryKey() {
		return NoPrimaryKey
	}

	return g.getItFrom(i, keys, table)
}

func (g *Gemini) getItFrom(i interface{}, keys []interface{}, table *TableMap) error {
	// TODO(ttacon)
	primaryKeys := table.PrimaryKey()
	if len(primaryKeys) != len(keys) {
		return fmt.Errorf(
			"to use get, must provide correct number of primary keys (expected %d, got %d",
			len(primaryKeys),
			len(keys),
		)
	}

	queryString := "select "
	for i, field := range table.Fields {
		if i != 0 {
			queryString += ", "
		}
		queryString += field.columnName
	}

	queryString += " from " + table.TableName + " where "

	for i, key := range primaryKeys {
		if i != 0 {
			queryString += " and "
		}
		// TODO(ttacon): right now this doesn't deal with struct tag names nor
		// ensuring the value at key[i] is a decent value (not struct or pointer)
		// also, what if that field is a Struct, we need to know how to set the id
		// correctly
		queryString += fmt.Sprintf("%s = %v", key.Name, keys[i])
	}

	// this currently won't work for MongoDB
	db, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}

	rows, err := db.Db.Query(queryString)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Insert(i interface{}) error {
	if reflect.TypeOf(i).Kind() != reflect.Ptr {
		return fmt.Errorf("cannot insert non pointer type")
	}

	e := reflect.ValueOf(i).Elem()
	tableName := tableNameForStruct(e.Type())

	// TODO(ttacon): perhaps we should be smart and try to just insert if there is only one db
	// even if we don't have a mapping from table to db
	dbInfo, ok := g.TableToDatabaseInfo[tableName]
	if !ok {
		return fmt.Errorf("table %s is not specified to interact with any db", tableName)
	}
	db := dbInfo.Db

	tMap, ok := g.StructsMap[tableName]
	if !ok {
		return fmt.Errorf("table %s does not have a table map", tableName)
	}

	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(MongoDB{}) {
		return dbInfo.MongoSesh.DB(dbInfo.DbName).C(tableName).Insert(i)
	}

	// TODO(ttacon): make smart mapping of table name to db driver and dialect
	query, args := insertQueryAndArgs(e, tMap, dbInfo.Dialect)
	// TODO(ttacon): use result (the underscored place)?
	var autoIncrId int64
	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(PostgresDialect{}) {
		rows := db.QueryRow(query, args...)
		if tMap.autoIncrField != nil {
			err := rows.Scan(&autoIncrId)
			if err != nil {
				return err
			}
		}
	} else {
		result, err := db.Exec(query, args...)
		if err != nil {
			return err
		}
		if tMap.autoIncrField != nil {
			autoIncrId, err = result.LastInsertId()
			if err != nil {
				return err
			}
		}
	}

	if tMap.autoIncrField != nil {
		fieldVal := e.FieldByName(tMap.autoIncrField.Name)
		k := fieldVal.Kind()

		if (k == reflect.Int) || (k == reflect.Int16) || (k == reflect.Int32) || (k == reflect.Int64) {
			fieldVal.SetInt(autoIncrId)
		} else if (k == reflect.Uint16) || (k == reflect.Uint32) || (k == reflect.Uint64) {
			fieldVal.SetUint(uint64(autoIncrId))
		}
	}

	return nil
}

func (g *Gemini) Delete(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Update(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Select(i interface{}, query string, args ...interface{}) error {
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)

	dbi, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}
	rows, err := dbi.Db.Query(query, args...)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Exec(query string, args ...interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) tableFor(i interface{}) *TableMap {
	var (
		tableName string
		val       = reflect.ValueOf(i)
	)

	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if v, ok := val.Type().FieldByName("TableInfo"); ok && v.Tag.Get("name") != "" {
		tableName = v.Tag.Get("name")
	} else {
		tableName = val.Type().Name()
	}

	// see if struct exists in table map
	if tMap, ok := g.StructsMap[tableName]; ok {
		return tMap
	}

	return TableMapFromStruct(i, tableName)
}
<commit_msg>Add exec, and more notes for refactor<commit_after>package gemini

import (
	"database/sql"
	"fmt"
	"reflect"
)

func (g *Gemini) Get(i interface{}, keys ...interface{}) error {
	// TODO(ttacon): really the key param should be variadic (for composite primary keys)
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)
	if !table.HasPrimaryKey() {
		return NoPrimaryKey
	}

	return g.getItFrom(i, keys, table)
}

func (g *Gemini) getItFrom(i interface{}, keys []interface{}, table *TableMap) error {
	// TODO(ttacon)
	primaryKeys := table.PrimaryKey()
	if len(primaryKeys) != len(keys) {
		return fmt.Errorf(
			"to use get, must provide correct number of primary keys (expected %d, got %d",
			len(primaryKeys),
			len(keys),
		)
	}

	queryString := "select "
	for i, field := range table.Fields {
		if i != 0 {
			queryString += ", "
		}
		queryString += field.columnName
	}

	queryString += " from " + table.TableName + " where "

	for i, key := range primaryKeys {
		if i != 0 {
			queryString += " and "
		}
		// TODO(ttacon): right now this doesn't deal with struct tag names nor
		// ensuring the value at key[i] is a decent value (not struct or pointer)
		// also, what if that field is a Struct, we need to know how to set the id
		// correctly
		queryString += fmt.Sprintf("%s = %v", key.Name, keys[i])
	}

	// this currently won't work for MongoDB
	db, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}

	rows, err := db.Db.Query(queryString)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Insert(i interface{}) error {
	if reflect.TypeOf(i).Kind() != reflect.Ptr {
		return fmt.Errorf("cannot insert non pointer type")
	}

	e := reflect.ValueOf(i).Elem()
	tableName := tableNameForStruct(e.Type())

	// TODO(ttacon): perhaps we should be smart and try to just insert if there is only one db
	// even if we don't have a mapping from table to db
	dbInfo, ok := g.TableToDatabaseInfo[tableName]
	if !ok {
		return fmt.Errorf("table %s is not specified to interact with any db", tableName)
	}
	db := dbInfo.Db

	tMap, ok := g.StructsMap[tableName]
	if !ok {
		return fmt.Errorf("table %s does not have a table map", tableName)
	}

	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(MongoDB{}) {
		return dbInfo.MongoSesh.DB(dbInfo.DbName).C(tableName).Insert(i)
	}

	// TODO(ttacon): make smart mapping of table name to db driver and dialect
	query, args := insertQueryAndArgs(e, tMap, dbInfo.Dialect)
	// TODO(ttacon): use result (the underscored place)?
	var autoIncrId int64
	if reflect.TypeOf(dbInfo.Dialect) == reflect.TypeOf(PostgresDialect{}) {
		rows := db.QueryRow(query, args...)
		if tMap.autoIncrField != nil {
			err := rows.Scan(&autoIncrId)
			if err != nil {
				return err
			}
		}
	} else {
		result, err := db.Exec(query, args...)
		if err != nil {
			return err
		}
		if tMap.autoIncrField != nil {
			autoIncrId, err = result.LastInsertId()
			if err != nil {
				return err
			}
		}
	}

	if tMap.autoIncrField != nil {
		fieldVal := e.FieldByName(tMap.autoIncrField.Name)
		k := fieldVal.Kind()

		if (k == reflect.Int) || (k == reflect.Int16) || (k == reflect.Int32) || (k == reflect.Int64) {
			fieldVal.SetInt(autoIncrId)
		} else if (k == reflect.Uint16) || (k == reflect.Uint32) || (k == reflect.Uint64) {
			fieldVal.SetUint(uint64(autoIncrId))
		}
	}

	return nil
}

func (g *Gemini) Delete(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Update(i interface{}) error {
	// TODO(ttacon)
	return nil
}

func (g *Gemini) Select(i interface{}, query string, args ...interface{}) error {
	val := reflect.ValueOf(i)
	if !val.IsValid() {
		return fmt.Errorf("invalid struct value")
	}

	keyVal := reflect.ValueOf(i)
	if !keyVal.IsValid() {
		return fmt.Errorf("invalid key value")
	}

	table := g.tableFor(i)

	dbi, ok := g.TableToDatabaseInfo[table.TableName]
	if !ok {
		return fmt.Errorf("no database info for table %q", table.TableName)
	}
	rows, err := dbi.Db.Query(query, args...)
	if err != nil {
		return err
	}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if !rows.Next() {
		if rows.Err() != nil {
			return rows.Err()
		}
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	target := make([]interface{}, len(cols))
	for i, col := range cols {
		// TODO(ttacon): go through evern column here
		// TODO(ttacon): need to make sure this is all safe
		f := v.FieldByName(table.ColumnNameToMapping[col].structFieldName)
		target[i] = f.Addr().Interface()
	}

	return rows.Scan(target...)
}

func (g *Gemini) Exec(query string, args ...interface{}) (sql.Result, error) {
	if len(g.Dbs) == 1 {
		return g.Dbs[0].Exec(query, args...)
	}
	return nil, NoDbSpecified
}

func (g *Gemini) ExecWithInfo(query string, args ...interface{}, info *DbInfo) (sql.Result, error) {
	// TODO(ttacon): allow users to attach db name to DbInfo so they don't
	// have to hold onto the db info
	return info.Exec(query, args...)
}

func (g *Gemini) tableFor(i interface{}) *TableMap {
	var (
		tableName string
		val       = reflect.ValueOf(i)
	)

	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if v, ok := val.Type().FieldByName("TableInfo"); ok && v.Tag.Get("name") != "" {
		tableName = v.Tag.Get("name")
	} else {
		tableName = val.Type().Name()
	}

	// see if struct exists in table map
	if tMap, ok := g.StructsMap[tableName]; ok {
		return tMap
	}

	return TableMapFromStruct(i, tableName)
}
<|endoftext|>