-
Notifications
You must be signed in to change notification settings - Fork 73
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
Override view name in querier #167
base: main
Are you sure you want to change the base?
Changes from all commits
db00617
d194063
27faa85
926b8bc
7136079
ea48221
6d5562e
dd045aa
d517892
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,25 +9,27 @@ import ( | |
|
||
// Querier performs queries and commands. | ||
type Querier struct { | ||
ctx context.Context | ||
dbtxCtx DBTXContext | ||
tag string | ||
ctx context.Context | ||
dbtxCtx DBTXContext | ||
tag string | ||
qualifiedViewName string | ||
Dialect | ||
Logger Logger | ||
} | ||
|
||
func newQuerier(ctx context.Context, dbtxCtx DBTXContext, tag string, dialect Dialect, logger Logger) *Querier { | ||
func newQuerier(ctx context.Context, dbtxCtx DBTXContext, tag, qualifiedViewName string, dialect Dialect, logger Logger) *Querier { | ||
return &Querier{ | ||
ctx: ctx, | ||
dbtxCtx: dbtxCtx, | ||
tag: tag, | ||
Dialect: dialect, | ||
Logger: logger, | ||
ctx: ctx, | ||
dbtxCtx: dbtxCtx, | ||
tag: tag, | ||
qualifiedViewName: qualifiedViewName, | ||
Dialect: dialect, | ||
Logger: logger, | ||
} | ||
} | ||
|
||
func (q *Querier) clone() *Querier { | ||
return newQuerier(q.ctx, q.dbtxCtx, q.tag, q.Dialect, q.Logger) | ||
return newQuerier(q.ctx, q.dbtxCtx, q.tag, q.qualifiedViewName, q.Dialect, q.Logger) | ||
} | ||
|
||
func (q *Querier) logBefore(query string, args []interface{}) { | ||
|
@@ -66,11 +68,20 @@ func (q *Querier) WithTag(format string, args ...interface{}) *Querier { | |
return newQ | ||
} | ||
|
||
// QualifiedView returns quoted qualified view name. | ||
// WithQualifiedViewName returns a copy of Querier with set qualified view name. | ||
// Returned Querier is tied to the same DB or TX. | ||
// TODO Support INSERT/UPDATE/DELETE. More test. | ||
func (q *Querier) WithQualifiedViewName(qualifiedViewName string) *Querier { | ||
newQ := q.clone() | ||
newQ.qualifiedViewName = qualifiedViewName | ||
return newQ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are losing tag here. |
||
} | ||
|
||
// QualifiedView returns quoted qualified view name of given view. | ||
func (q *Querier) QualifiedView(view View) string { | ||
v := q.QuoteIdentifier(view.Name()) | ||
if view.Schema() != "" { | ||
v = q.QuoteIdentifier(view.Schema()) + "." + v | ||
if s := view.Schema(); s != "" { | ||
v = q.QuoteIdentifier(s) + "." + v | ||
} | ||
return v | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,6 +85,20 @@ func ExampleQuerier_WithContext() { | |
_, _ = DB.WithContext(ctx).SelectAllFrom(ProjectTable, "") | ||
} | ||
|
||
func ExampleQuerier_WithQualifiedViewName() { | ||
_, err := DB.WithQualifiedViewName("people_0").FindByPrimaryKeyFrom(PersonTable, 1) | ||
AlekSi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if err != reform.ErrNoRows { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Optional linters] reported by reviewdog 🐶 |
||
log.Fatal(err) | ||
} | ||
person, err := DB.WithQualifiedViewName("people_1").FindByPrimaryKeyFrom(PersonTable, 1) | ||
AlekSi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(person) | ||
// Output: | ||
// ID: 1 (int32), GroupID: 65534 (*int32), Name: `Denis Mills` (string), Email: <nil> (*string), CreatedAt: 2009-11-10 23:00:00 +0000 UTC (time.Time), UpdatedAt: <nil> (*time.Time) | ||
} | ||
|
||
func ExampleQuerier_SelectRows() { | ||
tail := fmt.Sprintf("WHERE created_at < %s ORDER BY id", DB.Placeholder(1)) | ||
y2010 := time.Date(2010, 1, 1, 0, 0, 0, 0, time.UTC) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,8 +42,12 @@ func (q *Querier) selectQuery(view View, tail string, limit1 bool) string { | |
query += " TOP 1" | ||
} | ||
|
||
return fmt.Sprintf("%s %s FROM %s %s", | ||
query, strings.Join(q.QualifiedColumns(view), ", "), q.QualifiedView(view), tail) | ||
from := q.QualifiedView(view) | ||
if q.qualifiedViewName != "" { | ||
from = q.qualifiedViewName + " AS " + from | ||
} | ||
|
||
return fmt.Sprintf("%s %s FROM %s %s", query, strings.Join(q.QualifiedColumns(view), ", "), from, tail) | ||
AlekSi marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we only change table name in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. understand, it's a neat way that only change the view name when making SQL, |
||
} | ||
|
||
// SelectOneTo queries str's View with tail and args and scans first result to str. | ||
|
@@ -120,8 +124,8 @@ func (q *Querier) SelectAllFrom(view View, tail string, args ...interface{}) (st | |
} | ||
|
||
// findTail returns a tail of SELECT query for given view, column and arg. | ||
func (q *Querier) findTail(view string, column string, arg interface{}, limit1 bool) (tail string, needArg bool) { | ||
qi := q.QuoteIdentifier(view) + "." + q.QuoteIdentifier(column) | ||
func (q *Querier) findTail(view View, column string, arg interface{}, limit1 bool) (tail string, needArg bool) { | ||
qi := q.QualifiedView(view) + "." + q.QuoteIdentifier(column) | ||
if arg == nil { | ||
tail = fmt.Sprintf("WHERE %s IS NULL", qi) | ||
} else { | ||
|
@@ -142,7 +146,7 @@ func (q *Querier) findTail(view string, column string, arg interface{}, limit1 b | |
// If there are no rows in result, it returns ErrNoRows. It also may return QueryRow(), Scan() | ||
// and AfterFinder errors. | ||
func (q *Querier) FindOneTo(str Struct, column string, arg interface{}) error { | ||
tail, needArg := q.findTail(str.View().Name(), column, arg, true) | ||
tail, needArg := q.findTail(str.View(), column, arg, true) | ||
if needArg { | ||
return q.SelectOneTo(str, tail, arg) | ||
} | ||
|
@@ -155,7 +159,7 @@ func (q *Querier) FindOneTo(str Struct, column string, arg interface{}) error { | |
// If there are no rows in result, it returns nil, ErrNoRows. It also may return QueryRow(), Scan() | ||
// and AfterFinder errors. | ||
func (q *Querier) FindOneFrom(view View, column string, arg interface{}) (Struct, error) { | ||
tail, needArg := q.findTail(view.Name(), column, arg, true) | ||
tail, needArg := q.findTail(view, column, arg, true) | ||
if needArg { | ||
return q.SelectOneFrom(view, tail, arg) | ||
} | ||
|
@@ -169,7 +173,7 @@ func (q *Querier) FindOneFrom(view View, column string, arg interface{}) (Struct | |
// | ||
// See SelectRows example for idiomatic usage. | ||
func (q *Querier) FindRows(view View, column string, arg interface{}) (*sql.Rows, error) { | ||
tail, needArg := q.findTail(view.Name(), column, arg, false) | ||
tail, needArg := q.findTail(view, column, arg, false) | ||
if needArg { | ||
return q.SelectRows(view, tail, arg) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ import ( | |
"gopkg.in/reform.v1/dialects/postgresql" | ||
"gopkg.in/reform.v1/dialects/sqlite3" | ||
"gopkg.in/reform.v1/dialects/sqlserver" | ||
. "gopkg.in/reform.v1/internal/test/models" | ||
) | ||
|
||
type ctxKey string | ||
|
@@ -161,3 +162,28 @@ func TestExecWithContext(t *testing.T) { | |
t.Fatalf("tx.Rollback: unhandled driver %T. err = %s", dbDriver, err) | ||
} | ||
} | ||
|
||
func (s *ReformSuite) TestQualifiedView() { | ||
switch s.q.Dialect { | ||
case postgresql.Dialect: | ||
s.Equal(`"people"`, s.q.QualifiedView(PersonTable)) | ||
s.Equal(`"people"`, s.q.WithQualifiedViewName("ignored").QualifiedView(PersonTable)) | ||
AlekSi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
s.Equal(`"legacy"."people"`, s.q.QualifiedView(LegacyPersonTable)) | ||
s.Equal(`"legacy"."people"`, s.q.WithQualifiedViewName("ignored").QualifiedView(LegacyPersonTable)) | ||
AlekSi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
case mysql.Dialect: | ||
s.Equal("`people`", s.q.QualifiedView(PersonTable)) | ||
s.Equal("`people`", s.q.WithQualifiedViewName("ignored").QualifiedView(PersonTable)) | ||
AlekSi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
case sqlite3.Dialect: | ||
s.Equal(`"people"`, s.q.QualifiedView(PersonTable)) | ||
s.Equal(`"people"`, s.q.WithQualifiedViewName("ignored").QualifiedView(PersonTable)) | ||
|
||
case mssql.Dialect, sqlserver.Dialect: | ||
AlekSi marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Optional linters] reported by reviewdog 🐶 |
||
s.Equal(`[people]`, s.q.QualifiedView(PersonTable)) | ||
s.Equal(`[people]`, s.q.WithQualifiedViewName("ignored").QualifiedView(PersonTable)) | ||
|
||
default: | ||
s.Fail("Unhandled dialect", s.q.Dialect.String()) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Optional linters] reported by reviewdog 🐶
querier.go:73: Line contains TODO/BUG/FIXME: "TODO Support INSERT/UPDATE/DELETE. More ..." (godox)