Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] Query Select uses wrong table name when ModelTableExpr is called #965

Closed
mingoal opened this issue Mar 25, 2024 · 2 comments
Closed

Comments

@mingoal
Copy link

mingoal commented Mar 25, 2024

bun@v1.1.17

When ModelTableExpr is called, query select constructs wrong SQL statement.

db.NewSelect().
    Model(&AliasTableName{}).
    ModelTableExpr("model_table_expr_name").
    Where("id = ?", id).
    Scan(context.Background())

The result will be

select alias_table_name.id from model_table_expr_name where ...

The root cause is query_select.go:(*SelectQuery).appendColumns doesn't check baseQuery.modelTableName, uses table alias directly.

The following code fixes this bug, for your reference.

func (q *SelectQuery) appendColumns(fmter schema.Formatter, b []byte) (_ []byte, err error) {
	start := len(b)

	tableName := q.table.SQLAlias
	if !q.baseQuery.modelTableName.IsZero() {
		tableName = schema.Safe(q.baseQuery.modelTableName.Query)
	}

	switch {
	case q.columns != nil:
		for i, col := range q.columns {
			if i > 0 {
				b = append(b, ", "...)
			}

			if col.Args == nil && q.table != nil {
				if field, ok := q.table.FieldMap[col.Query]; ok {
					b = append(b, tableName...)
					b = append(b, '.')
					b = append(b, field.SQLName...)
					continue
				}
			}

			b, err = col.AppendQuery(fmter, b)
			if err != nil {
				return nil, err
			}
		}
	case q.table != nil:
		if len(q.table.Fields) > 10 && fmter.IsNop() {
			b = append(b, tableName...)
			b = append(b, '.')
			b = fmter.Dialect().AppendString(b, fmt.Sprintf("%d columns", len(q.table.Fields)))
		} else {
			b = appendColumns(b, tableName, q.table.Fields)
		}
	default:
		b = append(b, '*')
	}

	if err := q.forEachInlineRelJoin(func(join *relationJoin) error {
		if len(b) != start {
			b = append(b, ", "...)
			start = len(b)
		}

		b, err = q.appendInlineRelColumns(fmter, b, join)
		if err != nil {
			return err
		}

		return nil
	}); err != nil {
		return nil, err
	}

	b = bytes.TrimSuffix(b, []byte(", "))

	return b, nil
}
@vmihailenco
Copy link
Member

You're supposed to include the alias in the expr: ModelTableExpr("model_table_expr_name AS table_alias"). Because of this, your code will fail when the alias is present.

@mingoal
Copy link
Author

mingoal commented Mar 26, 2024

You're supposed to include the alias in the expr: ModelTableExpr("model_table_expr_name AS table_alias"). Because of this, your code will fail when the alias is present.

But insert/update don't require to do it. I suppose select would align with other operations.

If this is a must action, it closed the door to use one model for several tables have different table name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants