jet/sqlbuilder/table.go

292 lines
6.7 KiB
Go
Raw Normal View History

// Modeling of tables. This is where query preparation starts
package sqlbuilder
import (
2019-06-05 17:15:20 +02:00
"errors"
)
2019-06-05 17:15:20 +02:00
type readableTable interface {
// Generates a select query on the current tableName.
SELECT(projection projection, projections ...projection) SelectStatement
2019-06-04 12:10:23 +02:00
// Creates a inner join tableName Expression using onCondition.
INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
2019-06-04 12:10:23 +02:00
// Creates a left join tableName Expression using onCondition.
LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
2019-06-04 12:10:23 +02:00
// Creates a right join tableName Expression using onCondition.
RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
2019-03-16 14:02:45 +01:00
// Creates a full join tableName Expression using onCondition.
2019-06-04 12:10:23 +02:00
FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
2019-03-16 14:02:45 +01:00
// Creates a cross join tableName Expression using onCondition.
2019-06-04 12:10:23 +02:00
CROSS_JOIN(table ReadableTable) ReadableTable
columns() []Column
}
// The sql tableName write interface.
2019-05-07 19:06:21 +02:00
type writableTable interface {
INSERT(column column, columns ...column) InsertStatement
UPDATE(column column, columns ...column) UpdateStatement
2019-06-04 12:10:23 +02:00
DELETE() DeleteStatement
2019-05-07 13:44:30 +02:00
2019-06-04 12:10:23 +02:00
LOCK() LockStatement
}
2019-06-05 17:15:20 +02:00
type ReadableTable interface {
readableTable
clause
}
type WritableTable interface {
writableTable
clause
}
type Table interface {
readableTable
writableTable
clause
SchemaName() string
TableName() string
AS(alias string)
}
type readableTableInterfaceImpl struct {
parent ReadableTable
}
// Generates a select query on the current tableName.
func (r *readableTableInterfaceImpl) SELECT(projection1 projection, projections ...projection) SelectStatement {
return newSelectStatement(r.parent, append([]projection{projection1}, projections...))
2019-06-05 17:15:20 +02:00
}
// Creates a inner join tableName Expression using onCondition.
func (r *readableTableInterfaceImpl) INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, innerJoin, onCondition)
}
// Creates a left join tableName Expression using onCondition.
func (r *readableTableInterfaceImpl) LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, leftJoin, onCondition)
}
// Creates a right join tableName Expression using onCondition.
func (r *readableTableInterfaceImpl) RIGHT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, rightJoin, onCondition)
}
func (r *readableTableInterfaceImpl) FULL_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable {
return newJoinTable(r.parent, table, fullJoin, onCondition)
}
func (r *readableTableInterfaceImpl) CROSS_JOIN(table ReadableTable) ReadableTable {
return newJoinTable(r.parent, table, crossJoin, nil)
}
type writableTableInterfaceImpl struct {
parent WritableTable
}
func (w *writableTableInterfaceImpl) INSERT(column column, columns ...column) InsertStatement {
return newInsertStatement(w.parent, unwindColumns(column, columns...))
2019-06-05 17:15:20 +02:00
}
func (w *writableTableInterfaceImpl) UPDATE(column column, columns ...column) UpdateStatement {
return newUpdateStatement(w.parent, unwindColumns(column, columns...))
2019-06-05 17:15:20 +02:00
}
func (w *writableTableInterfaceImpl) DELETE() DeleteStatement {
return newDeleteStatement(w.parent)
}
func (w *writableTableInterfaceImpl) LOCK() LockStatement {
return LOCK(w.parent)
}
2019-06-05 17:15:20 +02:00
func NewTable(schemaName, name string, columns ...Column) Table {
t := &tableImpl{
2019-05-05 13:49:24 +02:00
schemaName: schemaName,
name: name,
columnList: columns,
}
for _, c := range columns {
2019-05-05 13:49:24 +02:00
c.setTableName(name)
}
2019-06-05 17:15:20 +02:00
t.readableTableInterfaceImpl.parent = t
t.writableTableInterfaceImpl.parent = t
return t
}
2019-06-05 17:15:20 +02:00
type tableImpl struct {
readableTableInterfaceImpl
writableTableInterfaceImpl
2019-05-05 13:49:24 +02:00
schemaName string
name string
alias string
columnList []Column
}
2019-06-05 17:15:20 +02:00
func (t *tableImpl) AS(alias string) {
2019-03-16 20:41:06 +01:00
t.alias = alias
for _, c := range t.columnList {
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-06-05 17:15:20 +02:00
func (t *tableImpl) SchemaName() string {
2019-04-07 09:58:12 +02:00
return t.schemaName
}
// Returns the tableName's name in the database
2019-06-05 17:15:20 +02:00
func (t *tableImpl) TableName() string {
return t.name
}
func (t *tableImpl) columns() []Column {
return t.columnList
2019-03-09 09:52:03 +01:00
}
2019-06-05 17:15:20 +02:00
func (t *tableImpl) serialize(statement statementType, out *queryData, options ...serializeOption) error {
2019-04-20 19:49:29 +02:00
if t == nil {
2019-06-05 17:15:20 +02:00
return errors.New("tableImpl is nil. ")
2019-03-09 09:52:03 +01:00
}
2019-06-17 12:05:52 +02:00
out.writeIdentifier(t.schemaName)
out.writeString(".")
2019-06-17 12:05:52 +02:00
out.writeIdentifier(t.name)
2019-03-16 20:41:06 +01:00
if len(t.alias) > 0 {
2019-06-17 12:05:52 +02:00
out.writeString("AS")
out.writeIdentifier(t.alias)
2019-03-16 20:41:06 +01:00
}
return nil
}
type joinType int
const (
2019-06-05 17:15:20 +02:00
innerJoin joinType = iota
leftJoin
rightJoin
fullJoin
crossJoin
)
// Join expressions are pseudo readable tables.
type joinTable struct {
2019-06-05 17:15:20 +02:00
readableTableInterfaceImpl
2019-06-04 12:10:23 +02:00
lhs ReadableTable
rhs ReadableTable
join_type joinType
onCondition BoolExpression
}
func newJoinTable(
2019-06-04 12:10:23 +02:00
lhs ReadableTable,
rhs ReadableTable,
join_type joinType,
2019-06-04 12:10:23 +02:00
onCondition BoolExpression) ReadableTable {
2019-06-05 17:15:20 +02:00
joinTable := &joinTable{
lhs: lhs,
rhs: rhs,
join_type: join_type,
onCondition: onCondition,
}
2019-03-16 14:02:45 +01:00
2019-06-05 17:15:20 +02:00
joinTable.readableTableInterfaceImpl.parent = joinTable
2019-03-16 14:02:45 +01:00
2019-06-05 17:15:20 +02:00
return joinTable
2019-03-16 14:02:45 +01:00
}
2019-04-07 09:58:12 +02:00
func (t *joinTable) SchemaName() string {
return ""
}
func (t *joinTable) TableName() string {
return ""
}
func (t *joinTable) columns() []Column {
return append(t.lhs.columns(), t.rhs.columns()...)
}
func (t *joinTable) serialize(statement statementType, out *queryData, options ...serializeOption) (err error) {
2019-05-13 12:33:11 +02:00
if t == nil {
return errors.New("Join table is nil. ")
}
2019-06-05 17:15:20 +02:00
if isNil(t.lhs) {
return errors.New("left hand side of join operation is nil table")
}
if err = t.lhs.serialize(statement, out); err != nil {
return
}
out.newLine()
2019-05-12 18:15:23 +02:00
switch t.join_type {
2019-06-05 17:15:20 +02:00
case innerJoin:
out.writeString("INNER JOIN")
case leftJoin:
2019-05-12 18:15:23 +02:00
out.writeString("LEFT JOIN")
2019-06-05 17:15:20 +02:00
case rightJoin:
2019-05-12 18:15:23 +02:00
out.writeString("RIGHT JOIN")
2019-06-05 17:15:20 +02:00
case fullJoin:
2019-05-12 18:15:23 +02:00
out.writeString("FULL JOIN")
2019-06-05 17:15:20 +02:00
case crossJoin:
2019-05-12 18:15:23 +02:00
out.writeString("CROSS JOIN")
}
2019-06-05 17:15:20 +02:00
if isNil(t.rhs) {
return errors.New("right hand side of join operation is nil table")
}
if err = t.rhs.serialize(statement, out); err != nil {
return
}
2019-06-05 17:15:20 +02:00
if t.onCondition == nil && t.join_type != crossJoin {
return errors.New("join condition is nil")
}
2019-03-16 14:02:45 +01:00
if t.onCondition != nil {
2019-06-05 17:15:20 +02:00
out.writeString("ON")
if err = t.onCondition.serialize(statement, out); err != nil {
2019-03-16 14:02:45 +01:00
return
}
}
return nil
}
func unwindColumns(column1 column, columns ...column) []column {
columnList := []column{}
if val, ok := column1.(ColumnList); ok {
for _, col := range val {
columnList = append(columnList, col)
}
columnList = append(columnList, columns...)
} else {
columnList = append(columnList, column1)
columnList = append(columnList, columns...)
}
return columnList
}