Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest from master #620

Merged
merged 2 commits into from Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .goreleaser.yml
Expand Up @@ -89,7 +89,8 @@ changelog:

brews:
-
github:
name: 'pop'
tap:
owner: gobuffalo
name: homebrew-tap
homepage: "https://gobuffalo.io/docs/db/getting-started"
Expand Down
8 changes: 4 additions & 4 deletions belongs_to.go
Expand Up @@ -19,15 +19,15 @@ func (c *Connection) BelongsToAs(model interface{}, as string) *Query {
// BelongsTo adds a "where" clause based on the "ID" of the
// "model" passed into it.
func (q *Query) BelongsTo(model interface{}) *Query {
m := &Model{Value: model}
m := NewModel(model, q.Connection.Context())
q.Where(fmt.Sprintf("%s = ?", m.associationName()), m.ID())
return q
}

// BelongsToAs adds a "where" clause based on the "ID" of the
// "model" passed into it, using an alias.
func (q *Query) BelongsToAs(model interface{}, as string) *Query {
m := &Model{Value: model}
m := NewModel(model, q.Connection.Context())
q.Where(fmt.Sprintf("%s = ?", as), m.ID())
return q
}
Expand All @@ -42,8 +42,8 @@ func (c *Connection) BelongsToThrough(bt, thru interface{}) *Query {
// through the associated "thru" model.
func (q *Query) BelongsToThrough(bt, thru interface{}) *Query {
q.belongsToThroughClauses = append(q.belongsToThroughClauses, belongsToThroughClause{
BelongsTo: &Model{Value: bt},
Through: &Model{Value: thru},
BelongsTo: NewModel(bt, q.Connection.Context()),
Through: NewModel(thru, q.Connection.Context()),
})
return q
}
7 changes: 4 additions & 3 deletions belongs_to_test.go
@@ -1,6 +1,7 @@
package pop

import (
"context"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -14,7 +15,7 @@ func Test_BelongsTo(t *testing.T) {

q := PDB.BelongsTo(&User{ID: 1})

m := &Model{Value: &Enemy{}}
m := NewModel(new(Enemy), context.Background())

sql, _ := q.ToSQL(m)
r.Equal(ts("SELECT enemies.A FROM enemies AS enemies WHERE user_id = ?"), sql)
Expand All @@ -28,7 +29,7 @@ func Test_BelongsToAs(t *testing.T) {

q := PDB.BelongsToAs(&User{ID: 1}, "u_id")

m := &Model{Value: &Enemy{}}
m := NewModel(new(Enemy), context.Background())

sql, _ := q.ToSQL(m)
r.Equal(ts("SELECT enemies.A FROM enemies AS enemies WHERE u_id = ?"), sql)
Expand All @@ -43,7 +44,7 @@ func Test_BelongsToThrough(t *testing.T) {
q := PDB.BelongsToThrough(&User{ID: 1}, &Friend{})
qs := "SELECT enemies.A FROM enemies AS enemies, good_friends AS good_friends WHERE good_friends.user_id = ? AND enemies.id = good_friends.enemy_id"

m := &Model{Value: &Enemy{}}
m := NewModel(new(Enemy), context.Background())
sql, _ := q.ToSQL(m)
r.Equal(ts(qs), sql)
}
14 changes: 8 additions & 6 deletions columns/columns.go
Expand Up @@ -13,6 +13,7 @@ type Columns struct {
lock *sync.RWMutex
TableName string
TableAlias string
IDField string
}

// Add a column to the list.
Expand Down Expand Up @@ -74,7 +75,7 @@ func (c *Columns) Add(names ...string) []*Column {
} else if xs[1] == "w" {
col.Readable = false
}
} else if col.Name == "id" {
} else if col.Name == c.IDField {
col.Writeable = false
}

Expand All @@ -98,7 +99,7 @@ func (c *Columns) Remove(names ...string) {

// Writeable gets a list of the writeable columns from the column list.
func (c Columns) Writeable() *WriteableColumns {
w := &WriteableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias)}
w := &WriteableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias, c.IDField)}
for _, col := range c.Cols {
if col.Writeable {
w.Cols[col.Name] = col
Expand All @@ -109,7 +110,7 @@ func (c Columns) Writeable() *WriteableColumns {

// Readable gets a list of the readable columns from the column list.
func (c Columns) Readable() *ReadableColumns {
w := &ReadableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias)}
w := &ReadableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias, c.IDField)}
for _, col := range c.Cols {
if col.Readable {
w.Cols[col.Name] = col
Expand Down Expand Up @@ -157,17 +158,18 @@ func (c Columns) SymbolizedString() string {
}

// NewColumns constructs a list of columns for a given table name.
func NewColumns(tableName string) Columns {
return NewColumnsWithAlias(tableName, "")
func NewColumns(tableName, idField string) Columns {
return NewColumnsWithAlias(tableName, "", idField)
}

// NewColumnsWithAlias constructs a list of columns for a given table
// name, using a given alias for the table.
func NewColumnsWithAlias(tableName string, tableAlias string) Columns {
func NewColumnsWithAlias(tableName, tableAlias, idField string) Columns {
return Columns{
lock: &sync.RWMutex{},
Cols: map[string]*Column{},
TableName: tableName,
TableAlias: tableAlias,
IDField: idField,
}
}
10 changes: 5 additions & 5 deletions columns/columns_for_struct.go
Expand Up @@ -6,17 +6,17 @@ import (

// ForStruct returns a Columns instance for
// the struct passed in.
func ForStruct(s interface{}, tableName string) (columns Columns) {
return ForStructWithAlias(s, tableName, "")
func ForStruct(s interface{}, tableName, idField string) (columns Columns) {
return ForStructWithAlias(s, tableName, "", idField)
}

// ForStructWithAlias returns a Columns instance for the struct passed in.
// If the tableAlias is not empty, it will be used.
func ForStructWithAlias(s interface{}, tableName string, tableAlias string) (columns Columns) {
columns = NewColumnsWithAlias(tableName, tableAlias)
func ForStructWithAlias(s interface{}, tableName, tableAlias, idField string) (columns Columns) {
columns = NewColumnsWithAlias(tableName, tableAlias, idField)
defer func() {
if r := recover(); r != nil {
columns = NewColumnsWithAlias(tableName, tableAlias)
columns = NewColumnsWithAlias(tableName, tableAlias, idField)
columns.Add("*")
}
}()
Expand Down
46 changes: 40 additions & 6 deletions columns/columns_test.go
Expand Up @@ -21,16 +21,16 @@ type foos []foo
func Test_Column_MapsSlice(t *testing.T) {
r := require.New(t)

c1 := columns.ForStruct(&foo{}, "foo")
c2 := columns.ForStruct(&foos{}, "foo")
c1 := columns.ForStruct(&foo{}, "foo", "id")
c2 := columns.ForStruct(&foos{}, "foo", "id")
r.Equal(c1.String(), c2.String())
}

func Test_Columns_Basics(t *testing.T) {
r := require.New(t)

for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
r.Equal(len(c.Cols), 4)
r.Equal(c.Cols["first_name"], &columns.Column{Name: "first_name", Writeable: false, Readable: true, SelectSQL: "first_name as f"})
r.Equal(c.Cols["LastName"], &columns.Column{Name: "LastName", Writeable: true, Readable: true, SelectSQL: "foo.LastName"})
Expand All @@ -43,7 +43,7 @@ func Test_Columns_Add(t *testing.T) {
r := require.New(t)

for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
r.Equal(len(c.Cols), 4)
c.Add("foo", "first_name")
r.Equal(len(c.Cols), 5)
Expand All @@ -55,7 +55,7 @@ func Test_Columns_Remove(t *testing.T) {
r := require.New(t)

for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
r.Equal(len(c.Cols), 4)
c.Remove("foo", "first_name")
r.Equal(len(c.Cols), 3)
Expand All @@ -75,9 +75,43 @@ func (fooQuoter) Quote(key string) string {
func Test_Columns_Sorted(t *testing.T) {
r := require.New(t)

c := columns.ForStruct(fooWithSuffix{}, "fooWithSuffix")
c := columns.ForStruct(fooWithSuffix{}, "fooWithSuffix", "id")
r.Equal(len(c.Cols), 2)
r.Equal(c.SymbolizedString(), ":amount, :amount_units")
r.Equal(c.String(), "amount, amount_units")
r.Equal(c.QuotedString(fooQuoter{}), "`amount`, `amount_units`")
}

func Test_Columns_IDField(t *testing.T) {
type withID struct {
ID string `db:"id"`
}

r := require.New(t)
c := columns.ForStruct(withID{}, "with_id", "id")
r.Equal(1, len(c.Cols), "%+v", c)
r.Equal(&columns.Column{Name: "id", Writeable: false, Readable: true, SelectSQL: "with_id.id"}, c.Cols["id"])
}

func Test_Columns_IDField_Readonly(t *testing.T) {
type withIDReadonly struct {
ID string `db:"id" rw:"r"`
}

r := require.New(t)
c := columns.ForStruct(withIDReadonly{}, "with_id_readonly", "id")
r.Equal(1, len(c.Cols), "%+v", c)
r.Equal(&columns.Column{Name: "id", Writeable: false, Readable: true, SelectSQL: "with_id_readonly.id"}, c.Cols["id"])
}

func Test_Columns_ID_Field_Not_ID(t *testing.T) {
type withNonStandardID struct {
PK string `db:"notid"`
}

r := require.New(t)

c := columns.ForStruct(withNonStandardID{}, "non_standard_id", "notid")
r.Equal(1, len(c.Cols), "%+v", c)
r.Equal(&columns.Column{Name: "notid", Writeable: false, Readable: true, SelectSQL: "non_standard_id.notid"}, c.Cols["notid"])
}
6 changes: 3 additions & 3 deletions columns/readable_columns_test.go
Expand Up @@ -10,7 +10,7 @@ import (
func Test_Columns_ReadableString(t *testing.T) {
r := require.New(t)
for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
u := c.Readable().String()
r.Equal(u, "LastName, first_name, read")
}
Expand All @@ -19,7 +19,7 @@ func Test_Columns_ReadableString(t *testing.T) {
func Test_Columns_Readable_SelectString(t *testing.T) {
r := require.New(t)
for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
u := c.Readable().SelectString()
r.Equal(u, "first_name as f, foo.LastName, foo.read")
}
Expand All @@ -28,7 +28,7 @@ func Test_Columns_Readable_SelectString(t *testing.T) {
func Test_Columns_ReadableString_Symbolized(t *testing.T) {
r := require.New(t)
for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
u := c.Readable().SymbolizedString()
r.Equal(u, ":LastName, :first_name, :read")
}
Expand Down
8 changes: 4 additions & 4 deletions columns/writeable_columns_test.go
Expand Up @@ -10,7 +10,7 @@ import (
func Test_Columns_WriteableString_Symbolized(t *testing.T) {
r := require.New(t)
for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
u := c.Writeable().SymbolizedString()
r.Equal(u, ":LastName, :write")
}
Expand All @@ -19,7 +19,7 @@ func Test_Columns_WriteableString_Symbolized(t *testing.T) {
func Test_Columns_UpdateString(t *testing.T) {
r := require.New(t)
for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
u := c.Writeable().UpdateString()
r.Equal(u, "LastName = :LastName, write = :write")
}
Expand All @@ -35,7 +35,7 @@ func Test_Columns_QuotedUpdateString(t *testing.T) {
r := require.New(t)
q := testQuoter{}
for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
u := c.Writeable().QuotedUpdateString(q)
r.Equal(u, "\"LastName\" = :LastName, \"write\" = :write")
}
Expand All @@ -44,7 +44,7 @@ func Test_Columns_QuotedUpdateString(t *testing.T) {
func Test_Columns_WriteableString(t *testing.T) {
r := require.New(t)
for _, f := range []interface{}{foo{}, &foo{}} {
c := columns.ForStruct(f, "foo")
c := columns.ForStruct(f, "foo", "id")
u := c.Writeable().String()
r.Equal(u, "LastName, write")
}
Expand Down
10 changes: 10 additions & 0 deletions connection.go
Expand Up @@ -33,6 +33,16 @@ func (c *Connection) URL() string {
return c.Dialect.URL()
}

// Context returns the connection's context set by "Context()" or context.TODO()
// if no context is set.
func (c *Connection) Context() context.Context {
if c, ok := c.Store.(interface{ Context() context.Context }); ok {
return c.Context()
}

return context.TODO()
}

// MigrationURL returns the datasource connection string used for running the migrations
func (c *Connection) MigrationURL() string {
return c.Dialect.MigrationURL()
Expand Down
7 changes: 6 additions & 1 deletion connection_details.go
Expand Up @@ -2,13 +2,14 @@ package pop

import (
"fmt"
"github.com/luna-duclos/instrumentedsql"
"net/url"
"regexp"
"strconv"
"strings"
"time"

"github.com/luna-duclos/instrumentedsql"

"github.com/gobuffalo/pop/v5/internal/defaults"
"github.com/gobuffalo/pop/v5/logging"
"github.com/pkg/errors"
Expand Down Expand Up @@ -179,6 +180,10 @@ func (cd *ConnectionDetails) OptionsString(s string) string {
}
if cd.Options != nil {
for k, v := range cd.Options {
if k == "migration_table_name" {
continue
}

s = fmt.Sprintf("%s&%s=%s", s, k, v)
}
}
Expand Down
19 changes: 19 additions & 0 deletions connection_details_test.go
Expand Up @@ -84,3 +84,22 @@ func Test_ConnectionDetails_Finalize_NoDB_NoURL(t *testing.T) {
err := cd.Finalize()
r.Error(err)
}

func Test_ConnectionDetails_OptionsString_Postgres(t *testing.T) {
r := require.New(t)
cd := &ConnectionDetails{
Dialect: "postgres",
Database: "database",
Host: "host",
Port: "1234",
User: "user",
Password: "pass",
Options: map[string]string{
"migration_table_name": "migrations",
"sslmode": "require",
},
}

r.Equal("sslmode=require", cd.OptionsString(""))
r.Equal("migrations", cd.MigrationTableName())
}
1 change: 1 addition & 0 deletions connection_instrumented.go
Expand Up @@ -3,6 +3,7 @@ package pop
import (
"database/sql"
"database/sql/driver"

mysqld "github.com/go-sql-driver/mysql"
"github.com/gobuffalo/pop/v5/logging"
pgx "github.com/jackc/pgx/v4/stdlib"
Expand Down
3 changes: 2 additions & 1 deletion connection_instrumented_nosqlite_test.go
Expand Up @@ -3,8 +3,9 @@
package pop

import (
"github.com/stretchr/testify/require"
"testing"

"github.com/stretchr/testify/require"
)

func TestInstrumentation_WithoutSqlite(t *testing.T) {
Expand Down