2022-11-02 17:49:03 +01:00
|
|
|
// Copyright 2022 The Xorm Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package statements
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"xorm.io/builder"
|
|
|
|
"xorm.io/xorm/dialects"
|
|
|
|
"xorm.io/xorm/internal/utils"
|
|
|
|
"xorm.io/xorm/schemas"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
2023-10-01 12:07:22 +02:00
|
|
|
func (statement *Statement) Join(joinOP string, joinTable interface{}, condition interface{}, args ...interface{}) *Statement {
|
|
|
|
statement.joins = append(statement.joins, join{
|
|
|
|
op: joinOP,
|
|
|
|
table: joinTable,
|
|
|
|
condition: condition,
|
|
|
|
args: args,
|
|
|
|
})
|
|
|
|
return statement
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) writeJoins(w *builder.BytesWriter) error {
|
|
|
|
for _, join := range statement.joins {
|
|
|
|
if err := statement.writeJoin(w, join); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-04-19 16:50:48 +02:00
|
|
|
func (statement *Statement) writeJoinTable(buf *builder.BytesWriter, join join) error {
|
2023-10-01 12:07:22 +02:00
|
|
|
switch tp := join.table.(type) {
|
2022-11-02 17:49:03 +01:00
|
|
|
case builder.Builder:
|
2023-10-01 12:07:22 +02:00
|
|
|
if _, err := fmt.Fprintf(buf, " ("); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := tp.WriteTo(statement.QuoteReplacer(buf)); err != nil {
|
|
|
|
return err
|
2022-11-02 17:49:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fields := strings.Split(tp.TableName(), ".")
|
|
|
|
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
|
|
|
|
aliasName = schemas.CommonQuoter.Trim(aliasName)
|
|
|
|
|
2023-10-01 12:07:22 +02:00
|
|
|
if _, err := fmt.Fprintf(buf, ") %s", statement.quote(aliasName)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-02 17:49:03 +01:00
|
|
|
case *builder.Builder:
|
2023-10-01 12:07:22 +02:00
|
|
|
if _, err := fmt.Fprintf(buf, " ("); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := tp.WriteTo(statement.QuoteReplacer(buf)); err != nil {
|
|
|
|
return err
|
2022-11-02 17:49:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fields := strings.Split(tp.TableName(), ".")
|
|
|
|
aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
|
|
|
|
aliasName = schemas.CommonQuoter.Trim(aliasName)
|
|
|
|
|
2023-10-01 12:07:22 +02:00
|
|
|
if _, err := fmt.Fprintf(buf, ") %s", statement.quote(aliasName)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-02 17:49:03 +01:00
|
|
|
default:
|
2023-10-01 12:07:22 +02:00
|
|
|
tbName := dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), join.table, true)
|
2022-11-02 17:49:03 +01:00
|
|
|
if !utils.IsSubQuery(tbName) {
|
2023-10-01 12:07:22 +02:00
|
|
|
var sb strings.Builder
|
|
|
|
if err := statement.dialect.Quoter().QuoteTo(&sb, tbName); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
tbName = sb.String()
|
2022-11-02 17:49:03 +01:00
|
|
|
} else {
|
|
|
|
tbName = statement.ReplaceQuote(tbName)
|
|
|
|
}
|
2023-10-01 12:07:22 +02:00
|
|
|
if _, err := fmt.Fprint(buf, " ", tbName); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-02 17:49:03 +01:00
|
|
|
}
|
2024-04-19 16:50:48 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (statement *Statement) writeJoin(buf *builder.BytesWriter, join join) error {
|
|
|
|
// write join operator
|
|
|
|
if _, err := fmt.Fprint(buf, " ", join.op, " JOIN"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// write join table or subquery
|
|
|
|
if err := statement.writeJoinTable(buf, join); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-02 17:49:03 +01:00
|
|
|
|
2023-10-01 12:07:22 +02:00
|
|
|
// write on condition
|
|
|
|
if _, err := fmt.Fprint(buf, " ON "); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-02 17:49:03 +01:00
|
|
|
|
2023-10-01 12:07:22 +02:00
|
|
|
switch condTp := join.condition.(type) {
|
|
|
|
case string:
|
|
|
|
if _, err := fmt.Fprint(buf, statement.ReplaceQuote(condTp)); err != nil {
|
2022-11-02 17:49:03 +01:00
|
|
|
return err
|
|
|
|
}
|
2023-10-01 12:07:22 +02:00
|
|
|
case builder.Cond:
|
|
|
|
if err := condTp.WriteTo(statement.QuoteReplacer(buf)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("unsupported join condition type: %v", condTp)
|
2022-11-02 17:49:03 +01:00
|
|
|
}
|
2023-10-01 12:07:22 +02:00
|
|
|
buf.Append(join.args...)
|
|
|
|
|
2022-11-02 17:49:03 +01:00
|
|
|
return nil
|
|
|
|
}
|
2024-04-19 16:50:48 +02:00
|
|
|
|
|
|
|
func (statement *Statement) convertJoinCondition(join join) (builder.Cond, error) {
|
|
|
|
switch condTp := join.condition.(type) {
|
|
|
|
case string:
|
|
|
|
return builder.Expr(statement.ReplaceQuote(condTp), join.args...), nil
|
|
|
|
case builder.Cond:
|
|
|
|
return condTp, nil
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported join condition type: %v", condTp)
|
|
|
|
}
|
|
|
|
}
|