jet/sqlbuilder/table.go

349 lines
7.4 KiB
Go
Raw Normal View History

// Modeling of tables. This is where query preparation starts
package sqlbuilder
import (
"github.com/dropbox/godropbox/errors"
)
2019-05-05 13:49:24 +02:00
type tableInterface interface {
clause
2019-04-07 09:58:12 +02:00
SchemaName() string
TableName() string
2019-05-05 13:49:24 +02:00
2019-05-07 19:06:21 +02:00
Columns() []column
2019-04-07 09:58:12 +02:00
}
// The sql tableName read interface. NOTE: NATURAL JOINs, and join "USING" clause
// are not supported.
2019-05-07 19:06:21 +02:00
type readableTable interface {
2019-05-05 13:49:24 +02:00
tableInterface
// Generates a select query on the current tableName.
2019-05-07 19:06:21 +02:00
SELECT(projections ...projection) selectStatement
// Creates a inner join tableName expression using onCondition.
2019-05-07 19:06:21 +02:00
INNER_JOIN(table readableTable, onCondition boolExpression) readableTable
// Creates a left join tableName expression using onCondition.
2019-05-07 19:06:21 +02:00
LEFT_JOIN(table readableTable, onCondition boolExpression) readableTable
// Creates a right join tableName expression using onCondition.
2019-05-07 19:06:21 +02:00
RIGHT_JOIN(table readableTable, onCondition boolExpression) readableTable
2019-03-16 14:02:45 +01:00
2019-05-07 19:06:21 +02:00
FULL_JOIN(table readableTable, onCondition boolExpression) readableTable
2019-03-16 14:02:45 +01:00
2019-05-07 19:06:21 +02:00
CROSS_JOIN(table readableTable) readableTable
}
// The sql tableName write interface.
2019-05-07 19:06:21 +02:00
type writableTable interface {
2019-05-05 13:49:24 +02:00
tableInterface
2019-05-07 19:06:21 +02:00
INSERT(columns ...column) insertStatement
UPDATE(columns ...column) updateStatement
DELETE() deleteStatement
2019-05-07 13:44:30 +02:00
LOCK() lockStatement
}
// Defines a physical tableName in the database that is both readable and writable.
// This function will panic if name is not valid
2019-05-07 19:06:21 +02:00
func NewTable(schemaName, name string, columns ...column) *Table {
t := &Table{
2019-05-05 13:49:24 +02:00
schemaName: schemaName,
name: name,
columns: columns,
}
for _, c := range columns {
2019-05-05 13:49:24 +02:00
c.setTableName(name)
}
return t
}
type Table struct {
2019-05-05 13:49:24 +02:00
schemaName string
name string
alias string
2019-05-07 19:06:21 +02:00
columns []column
}
2019-05-07 19:06:21 +02:00
func (t *Table) Column(name string) column {
return &baseColumn{
name: name,
nullable: NotNullable,
tableName: t.name,
}
}
2019-03-16 20:41:06 +01:00
func (t *Table) SetAlias(alias string) {
t.alias = alias
for _, c := range t.columns {
2019-05-05 13:49:24 +02:00
c.setTableName(alias)
2019-03-16 20:41:06 +01:00
}
}
// Returns the tableName's name in the database
2019-04-07 09:58:12 +02:00
func (t *Table) SchemaName() string {
return t.schemaName
}
// Returns the tableName's name in the database
func (t *Table) TableName() string {
return t.name
}
2019-04-07 09:58:12 +02:00
func (t *Table) SchemaTableName() string {
2019-03-09 09:52:03 +01:00
return t.schemaName
}
// Returns a list of the tableName's columns
2019-05-07 19:06:21 +02:00
func (t *Table) Columns() []column {
return t.columns
}
// Generates the sql string for the current tableName expression. Note: the
// generated string may not be a valid/executable sql statement.
func (t *Table) serialize(statement statementType, out *queryData) error {
2019-04-20 19:49:29 +02:00
if t == nil {
return errors.Newf("nil tableName.")
2019-03-09 09:52:03 +01:00
}
out.writeString(t.schemaName)
out.writeString(".")
out.writeString(t.TableName())
2019-03-16 20:41:06 +01:00
if len(t.alias) > 0 {
out.writeString(" AS ")
out.writeString(t.alias)
2019-03-16 20:41:06 +01:00
}
return nil
}
// Generates a select query on the current tableName.
2019-05-07 19:06:21 +02:00
func (t *Table) SELECT(projections ...projection) selectStatement {
return newSelectStatement(t, projections)
}
// Creates a inner join tableName expression using onCondition.
func (t *Table) INNER_JOIN(
2019-05-07 19:06:21 +02:00
table readableTable,
onCondition boolExpression) readableTable {
return InnerJoinOn(t, table, onCondition)
}
// Creates a left join tableName expression using onCondition.
func (t *Table) LEFT_JOIN(
2019-05-07 19:06:21 +02:00
table readableTable,
onCondition boolExpression) readableTable {
return LeftJoinOn(t, table, onCondition)
}
// Creates a right join tableName expression using onCondition.
func (t *Table) RIGHT_JOIN(
2019-05-07 19:06:21 +02:00
table readableTable,
onCondition boolExpression) readableTable {
return RightJoinOn(t, table, onCondition)
}
2019-05-07 19:06:21 +02:00
func (t *Table) FULL_JOIN(table readableTable, onCondition boolExpression) readableTable {
2019-03-31 14:07:58 +02:00
return FullJoin(t, table, onCondition)
2019-03-16 14:02:45 +01:00
}
2019-05-07 19:06:21 +02:00
func (t *Table) CROSS_JOIN(table readableTable) readableTable {
2019-03-16 14:02:45 +01:00
return CrossJoin(t, table)
}
2019-05-07 19:06:21 +02:00
func (t *Table) INSERT(columns ...column) insertStatement {
return newInsertStatement(t, columns...)
}
2019-05-07 19:06:21 +02:00
func (t *Table) UPDATE(columns ...column) updateStatement {
2019-04-14 17:55:10 +02:00
return newUpdateStatement(t, columns)
}
2019-05-07 19:06:21 +02:00
func (t *Table) DELETE() deleteStatement {
return newDeleteStatement(t)
}
2019-05-07 13:44:30 +02:00
func (t *Table) LOCK() lockStatement {
return LOCK(t)
}
type joinType int
const (
INNER_JOIN joinType = iota
LEFT_JOIN
RIGHT_JOIN
2019-03-16 14:02:45 +01:00
FULL_JOIN
CROSS_JOIN
)
// Join expressions are pseudo readable tables.
type joinTable struct {
2019-05-07 19:06:21 +02:00
lhs readableTable
rhs readableTable
join_type joinType
2019-05-07 19:06:21 +02:00
onCondition boolExpression
}
func newJoinTable(
2019-05-07 19:06:21 +02:00
lhs readableTable,
rhs readableTable,
join_type joinType,
2019-05-07 19:06:21 +02:00
onCondition boolExpression) readableTable {
return &joinTable{
lhs: lhs,
rhs: rhs,
join_type: join_type,
onCondition: onCondition,
}
}
func InnerJoinOn(
2019-05-07 19:06:21 +02:00
lhs readableTable,
rhs readableTable,
onCondition boolExpression) readableTable {
return newJoinTable(lhs, rhs, INNER_JOIN, onCondition)
}
func LeftJoinOn(
2019-05-07 19:06:21 +02:00
lhs readableTable,
rhs readableTable,
onCondition boolExpression) readableTable {
return newJoinTable(lhs, rhs, LEFT_JOIN, onCondition)
}
func RightJoinOn(
2019-05-07 19:06:21 +02:00
lhs readableTable,
rhs readableTable,
onCondition boolExpression) readableTable {
return newJoinTable(lhs, rhs, RIGHT_JOIN, onCondition)
}
2019-03-16 14:02:45 +01:00
func FullJoin(
2019-05-07 19:06:21 +02:00
lhs readableTable,
rhs readableTable,
onCondition boolExpression) readableTable {
2019-03-16 14:02:45 +01:00
return newJoinTable(lhs, rhs, FULL_JOIN, onCondition)
}
func CrossJoin(
2019-05-07 19:06:21 +02:00
lhs readableTable,
rhs readableTable) readableTable {
2019-03-16 14:02:45 +01:00
return newJoinTable(lhs, rhs, CROSS_JOIN, nil)
}
2019-04-07 09:58:12 +02:00
func (t *joinTable) SchemaName() string {
return ""
}
func (t *joinTable) TableName() string {
return ""
}
2019-05-07 19:06:21 +02:00
func (t *joinTable) Columns() []column {
columns := make([]column, 0)
columns = append(columns, t.lhs.Columns()...)
columns = append(columns, t.rhs.Columns()...)
return columns
}
2019-05-07 19:06:21 +02:00
func (t *joinTable) Column(name string) column {
2019-05-05 13:49:24 +02:00
return &baseColumn{
name: name,
nullable: NotNullable,
}
}
func (t *joinTable) serialize(statement statementType, out *queryData) (err error) {
if t.lhs == nil {
return errors.Newf("nil lhs.")
}
if t.rhs == nil {
return errors.Newf("nil rhs.")
}
2019-03-16 14:02:45 +01:00
if t.onCondition == nil && t.join_type != CROSS_JOIN {
return errors.Newf("nil onCondition.")
}
if err = t.lhs.serialize(statement, out); err != nil {
return
}
switch t.join_type {
case INNER_JOIN:
out.writeString(" JOIN ")
case LEFT_JOIN:
out.writeString(" LEFT JOIN ")
case RIGHT_JOIN:
out.writeString(" RIGHT JOIN ")
2019-03-16 14:02:45 +01:00
case FULL_JOIN:
out.writeString(" FULL JOIN ")
2019-03-16 14:02:45 +01:00
case CROSS_JOIN:
out.writeString(" CROSS JOIN ")
}
if err = t.rhs.serialize(statement, out); err != nil {
return
}
2019-03-16 14:02:45 +01:00
if t.onCondition != nil {
out.writeString(" ON ")
if err = t.onCondition.serialize(statement, out); err != nil {
2019-03-16 14:02:45 +01:00
return
}
}
return nil
}
2019-05-07 19:06:21 +02:00
func (t *joinTable) SELECT(projections ...projection) selectStatement {
return newSelectStatement(t, projections)
}
func (t *joinTable) INNER_JOIN(
2019-05-07 19:06:21 +02:00
table readableTable,
onCondition boolExpression) readableTable {
return InnerJoinOn(t, table, onCondition)
}
func (t *joinTable) LEFT_JOIN(
2019-05-07 19:06:21 +02:00
table readableTable,
onCondition boolExpression) readableTable {
return LeftJoinOn(t, table, onCondition)
}
2019-05-07 19:06:21 +02:00
func (t *joinTable) FULL_JOIN(table readableTable, onCondition boolExpression) readableTable {
2019-03-31 14:07:58 +02:00
return FullJoin(t, table, onCondition)
2019-03-16 14:02:45 +01:00
}
2019-05-07 19:06:21 +02:00
func (t *joinTable) CROSS_JOIN(table readableTable) readableTable {
2019-03-16 14:02:45 +01:00
return CrossJoin(t, table)
}
func (t *joinTable) RIGHT_JOIN(
2019-05-07 19:06:21 +02:00
table readableTable,
onCondition boolExpression) readableTable {
return RightJoinOn(t, table, onCondition)
}