Extend Table join interface.
This commit is contained in:
parent
8e57dcc32f
commit
ba3cd37734
3 changed files with 78 additions and 7 deletions
|
|
@ -4,6 +4,7 @@ package sqlbuilder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"github.com/dropbox/godropbox/database/sqltypes"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/dropbox/godropbox/errors"
|
"github.com/dropbox/godropbox/errors"
|
||||||
|
|
@ -14,6 +15,7 @@ import (
|
||||||
// Representation of a table for query generation
|
// Representation of a table for query generation
|
||||||
type Column interface {
|
type Column interface {
|
||||||
isProjectionInterface
|
isProjectionInterface
|
||||||
|
isExpressionInterface
|
||||||
|
|
||||||
Name() string
|
Name() string
|
||||||
// Serialization for use in column lists
|
// Serialization for use in column lists
|
||||||
|
|
@ -24,6 +26,14 @@ type Column interface {
|
||||||
// Internal function for tracking table that a column belongs to
|
// Internal function for tracking table that a column belongs to
|
||||||
// for the purpose of serialization
|
// for the purpose of serialization
|
||||||
setTableName(table string) error
|
setTableName(table string) error
|
||||||
|
|
||||||
|
Eq(rhs Expression) BoolExpression
|
||||||
|
|
||||||
|
Gte(rhs Expression) BoolExpression
|
||||||
|
GteLiteral(rhs interface{}) BoolExpression
|
||||||
|
|
||||||
|
Lte(rhs Expression) BoolExpression
|
||||||
|
LteLiteral(rhs interface{}) BoolExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
type NullableColumn bool
|
type NullableColumn bool
|
||||||
|
|
@ -37,7 +47,6 @@ const (
|
||||||
type NonAliasColumn interface {
|
type NonAliasColumn interface {
|
||||||
Column
|
Column
|
||||||
isOrderByClauseInterface
|
isOrderByClauseInterface
|
||||||
isExpressionInterface
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Collation string
|
type Collation string
|
||||||
|
|
@ -94,6 +103,26 @@ func (c *baseColumn) SerializeSql(out *bytes.Buffer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *baseColumn) Eq(rhs Expression) BoolExpression {
|
||||||
|
return Eq(c, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *baseColumn) Gte(rhs Expression) BoolExpression {
|
||||||
|
return Gte(c, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *baseColumn) GteLiteral(rhs interface{}) BoolExpression {
|
||||||
|
return Gte(c, Literal(rhs))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *baseColumn) Lte(rhs Expression) BoolExpression {
|
||||||
|
return Lte(c, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *baseColumn) LteLiteral(literal interface{}) BoolExpression {
|
||||||
|
return Lte(c, Literal(literal))
|
||||||
|
}
|
||||||
|
|
||||||
type bytesColumn struct {
|
type bytesColumn struct {
|
||||||
baseColumn
|
baseColumn
|
||||||
isExpression
|
isExpression
|
||||||
|
|
@ -305,3 +334,27 @@ func (c *deferredLookupColumn) setTableName(table string) error {
|
||||||
"Lookup column '%s' should never have setTableName called on it",
|
"Lookup column '%s' should never have setTableName called on it",
|
||||||
c.colName)
|
c.colName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *deferredLookupColumn) Eq(rhs Expression) BoolExpression {
|
||||||
|
lit, ok := rhs.(*literalExpression)
|
||||||
|
if ok && sqltypes.Value(lit.value).IsNull() {
|
||||||
|
return newBoolExpression(c, rhs, []byte(" IS "))
|
||||||
|
}
|
||||||
|
return newBoolExpression(c, rhs, []byte(" = "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *deferredLookupColumn) Gte(rhs Expression) BoolExpression {
|
||||||
|
return Gte(c, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *deferredLookupColumn) GteLiteral(rhs interface{}) BoolExpression {
|
||||||
|
return Gte(c, Literal(rhs))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *deferredLookupColumn) Lte(rhs Expression) BoolExpression {
|
||||||
|
return Lte(c, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *deferredLookupColumn) LteLiteral(literal interface{}) BoolExpression {
|
||||||
|
return Lte(c, Literal(literal))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ type ReadableTable interface {
|
||||||
// Creates a inner join table expression using onCondition.
|
// Creates a inner join table expression using onCondition.
|
||||||
InnerJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable
|
InnerJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||||
|
|
||||||
|
InnerJoinUsing(table ReadableTable, col1 Column, col2 Column) ReadableTable
|
||||||
|
|
||||||
// Creates a left join table expression using onCondition.
|
// Creates a left join table expression using onCondition.
|
||||||
LeftJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable
|
LeftJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable
|
||||||
|
|
||||||
|
|
@ -170,6 +172,14 @@ func (t *Table) InnerJoinOn(
|
||||||
return InnerJoinOn(t, table, onCondition)
|
return InnerJoinOn(t, table, onCondition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Table) InnerJoinUsing(
|
||||||
|
table ReadableTable,
|
||||||
|
col1 Column,
|
||||||
|
col2 Column) ReadableTable {
|
||||||
|
|
||||||
|
return InnerJoinOn(t, table, col1.Eq(col2))
|
||||||
|
}
|
||||||
|
|
||||||
// Creates a left join table expression using onCondition.
|
// Creates a left join table expression using onCondition.
|
||||||
func (t *Table) LeftJoinOn(
|
func (t *Table) LeftJoinOn(
|
||||||
table ReadableTable,
|
table ReadableTable,
|
||||||
|
|
@ -308,6 +318,14 @@ func (t *joinTable) InnerJoinOn(
|
||||||
return InnerJoinOn(t, table, onCondition)
|
return InnerJoinOn(t, table, onCondition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *joinTable) InnerJoinUsing(
|
||||||
|
table ReadableTable,
|
||||||
|
col1 Column,
|
||||||
|
col2 Column) ReadableTable {
|
||||||
|
|
||||||
|
return InnerJoinOn(t, table, col1.Eq(col2))
|
||||||
|
}
|
||||||
|
|
||||||
func (t *joinTable) LeftJoinOn(
|
func (t *joinTable) LeftJoinOn(
|
||||||
table ReadableTable,
|
table ReadableTable,
|
||||||
onCondition BoolExpression) ReadableTable {
|
onCondition BoolExpression) ReadableTable {
|
||||||
|
|
|
||||||
|
|
@ -134,11 +134,11 @@ func TestSelect_ScanToSlice(t *testing.T) {
|
||||||
func TestJoinQueryStruct(t *testing.T) {
|
func TestJoinQueryStruct(t *testing.T) {
|
||||||
|
|
||||||
query := FilmActor.
|
query := FilmActor.
|
||||||
InnerJoinOn(Actor, sqlbuilder.Eq(FilmActor.ActorID, Actor.ActorID)).
|
InnerJoinUsing(Actor, FilmActor.ActorID, Actor.ActorID).
|
||||||
InnerJoinOn(Film, sqlbuilder.Eq(FilmActor.FilmID, Film.FilmID)).
|
InnerJoinUsing(Film, FilmActor.FilmID, Film.FilmID).
|
||||||
InnerJoinOn(Language, sqlbuilder.Eq(Film.LanguageID, Language.LanguageID)).
|
InnerJoinUsing(Language, Film.LanguageID, Language.LanguageID).
|
||||||
Select(FilmActor.AllColumns, Film.AllColumns, Language.AllColumns, Actor.AllColumns).
|
Select(FilmActor.AllColumns, Film.AllColumns, Language.AllColumns, Actor.AllColumns).
|
||||||
Where(sqlbuilder.And(sqlbuilder.Gte(FilmActor.ActorID, sqlbuilder.Literal(1)), sqlbuilder.Lte(FilmActor.ActorID, sqlbuilder.Literal(2))))
|
Where(sqlbuilder.And(FilmActor.ActorID.GteLiteral(1), FilmActor.ActorID.LteLiteral(2)))
|
||||||
|
|
||||||
queryStr, err := query.String()
|
queryStr, err := query.String()
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -165,7 +165,7 @@ func TestJoinQuerySlice(t *testing.T) {
|
||||||
filmsPerLanguage := []FilmsPerLanguage{}
|
filmsPerLanguage := []FilmsPerLanguage{}
|
||||||
limit := 15
|
limit := 15
|
||||||
|
|
||||||
query := Film.InnerJoinOn(Language, sqlbuilder.Eq(Film.LanguageID, Language.LanguageID)).
|
query := Film.InnerJoinUsing(Language, Film.LanguageID, Language.LanguageID).
|
||||||
Select(Language.AllColumns, Film.AllColumns).
|
Select(Language.AllColumns, Film.AllColumns).
|
||||||
Limit(15)
|
Limit(15)
|
||||||
|
|
||||||
|
|
@ -205,7 +205,7 @@ func TestJoinQuerySliceWithPtrs(t *testing.T) {
|
||||||
|
|
||||||
limit := int64(3)
|
limit := int64(3)
|
||||||
|
|
||||||
query := Film.InnerJoinOn(Language, sqlbuilder.Eq(Film.LanguageID, Language.LanguageID)).
|
query := Film.InnerJoinUsing(Language, Film.LanguageID, Language.LanguageID).
|
||||||
Select(Language.AllColumns, Film.AllColumns).
|
Select(Language.AllColumns, Film.AllColumns).
|
||||||
Limit(limit)
|
Limit(limit)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue