2019-03-02 12:34:08 +01:00
|
|
|
// Modeling of tables. This is where query preparation starts
|
|
|
|
|
|
2019-06-21 13:56:57 +02:00
|
|
|
package jet
|
2019-03-02 12:34:08 +01:00
|
|
|
|
|
|
|
|
import (
|
2019-06-05 17:15:20 +02:00
|
|
|
"errors"
|
2019-03-02 12:34:08 +01:00
|
|
|
)
|
|
|
|
|
|
2019-06-05 17:15:20 +02:00
|
|
|
type readableTable interface {
|
2019-03-30 10:17:32 +01:00
|
|
|
// Generates a select query on the current tableName.
|
2019-06-15 13:58:45 +02:00
|
|
|
SELECT(projection projection, projections ...projection) SelectStatement
|
2019-03-02 12:34:08 +01:00
|
|
|
|
2019-06-04 12:10:23 +02:00
|
|
|
// Creates a inner join tableName Expression using onCondition.
|
|
|
|
|
INNER_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
2019-03-02 12:34:08 +01:00
|
|
|
|
2019-06-04 12:10:23 +02:00
|
|
|
// Creates a left join tableName Expression using onCondition.
|
|
|
|
|
LEFT_JOIN(table ReadableTable, onCondition BoolExpression) ReadableTable
|
2019-03-02 12:34:08 +01:00
|
|
|
|
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
|
|
|
|
2019-06-14 14:35:50 +02: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
|
|
|
|
2019-06-14 14:35:50 +02:00
|
|
|
// Creates a cross join tableName Expression using onCondition.
|
2019-06-04 12:10:23 +02:00
|
|
|
CROSS_JOIN(table ReadableTable) ReadableTable
|
2019-06-18 14:35:32 +02:00
|
|
|
|
|
|
|
|
columns() []Column
|
2019-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:17:32 +01:00
|
|
|
// The sql tableName write interface.
|
2019-05-07 19:06:21 +02:00
|
|
|
type writableTable interface {
|
2019-06-14 14:35:50 +02:00
|
|
|
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-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
|
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.
|
2019-06-15 13:58:45 +02:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 14:35:50 +02:00
|
|
|
func (w *writableTableInterfaceImpl) INSERT(column column, columns ...column) InsertStatement {
|
|
|
|
|
return newInsertStatement(w.parent, unwindColumns(column, columns...))
|
2019-06-05 17:15:20 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-14 14:35:50 +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-03-02 12:34:08 +01:00
|
|
|
|
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,
|
2019-06-18 14:35:32 +02:00
|
|
|
columnList: columns,
|
2019-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
for _, c := range columns {
|
2019-05-05 13:49:24 +02:00
|
|
|
c.setTableName(name)
|
2019-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-05 17:15:20 +02:00
|
|
|
t.readableTableInterfaceImpl.parent = t
|
|
|
|
|
t.writableTableInterfaceImpl.parent = t
|
|
|
|
|
|
2019-03-02 12:34:08 +01:00
|
|
|
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
|
2019-06-18 14:35:32 +02:00
|
|
|
columnList []Column
|
2019-03-30 10:17:32 +01:00
|
|
|
}
|
2019-03-02 12:34:08 +01:00
|
|
|
|
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
|
|
|
|
|
|
2019-06-18 14:35:32 +02:00
|
|
|
for _, c := range t.columnList {
|
2019-05-05 13:49:24 +02:00
|
|
|
c.setTableName(alias)
|
2019-03-16 20:41:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:17:32 +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 {
|
2019-03-02 12:34:08 +01:00
|
|
|
return t.name
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-18 14:35:32 +02:00
|
|
|
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-04-29 14:39:48 +02:00
|
|
|
|
2019-06-17 12:05:52 +02:00
|
|
|
out.writeIdentifier(t.schemaName)
|
2019-05-08 13:47:01 +02:00
|
|
|
out.writeString(".")
|
2019-06-17 12:05:52 +02:00
|
|
|
out.writeIdentifier(t.name)
|
2019-03-02 12:34:08 +01:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-03-02 12:34:08 +01:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type joinType int
|
|
|
|
|
|
|
|
|
|
const (
|
2019-06-05 17:15:20 +02:00
|
|
|
innerJoin joinType = iota
|
|
|
|
|
leftJoin
|
|
|
|
|
rightJoin
|
|
|
|
|
fullJoin
|
|
|
|
|
crossJoin
|
2019-03-02 12:34:08 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 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
|
2019-03-02 12:34:08 +01:00
|
|
|
join_type joinType
|
2019-05-31 12:59:57 +02:00
|
|
|
onCondition BoolExpression
|
2019-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newJoinTable(
|
2019-06-04 12:10:23 +02:00
|
|
|
lhs ReadableTable,
|
|
|
|
|
rhs ReadableTable,
|
2019-03-02 12:34:08 +01:00
|
|
|
join_type joinType,
|
2019-06-04 12:10:23 +02:00
|
|
|
onCondition BoolExpression) ReadableTable {
|
2019-03-02 12:34:08 +01:00
|
|
|
|
2019-06-05 17:15:20 +02:00
|
|
|
joinTable := &joinTable{
|
2019-03-02 12:34:08 +01:00
|
|
|
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 ""
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-18 14:35:32 +02:00
|
|
|
func (t *joinTable) columns() []Column {
|
|
|
|
|
return append(t.lhs.columns(), t.rhs.columns()...)
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-31 14:37:51 +02:00
|
|
|
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")
|
2019-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-08 13:47:01 +02:00
|
|
|
if err = t.lhs.serialize(statement, out); err != nil {
|
2019-03-02 12:34:08 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 14:35:50 +02:00
|
|
|
out.newLine()
|
2019-05-12 18:15:23 +02:00
|
|
|
|
2019-03-02 12:34:08 +01: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-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-05 17:15:20 +02:00
|
|
|
if isNil(t.rhs) {
|
|
|
|
|
return errors.New("right hand side of join operation is nil table")
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-08 13:47:01 +02:00
|
|
|
if err = t.rhs.serialize(statement, out); err != nil {
|
2019-03-02 12:34:08 +01:00
|
|
|
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")
|
2019-05-08 13:47:01 +02:00
|
|
|
if err = t.onCondition.serialize(statement, out); err != nil {
|
2019-03-16 14:02:45 +01:00
|
|
|
return
|
|
|
|
|
}
|
2019-03-02 12:34:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-06-14 14:35:50 +02:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|