Files
db/delete_dataset.go
T
whatandClaude 304d553b3c docs: Add CLAUDE.md with codebase guidance
Create comprehensive documentation for future Claude Code instances working in this repository, including:
- Development commands for testing, building, and code quality
- Core architecture overview of the SQL query builder system
- Directory structure and component explanations
- Testing patterns and conventions
- Key dependencies and their purposes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-27 15:47:28 +08:00

260 lines
8.1 KiB
Go

package db
import (
"git.fsdpf.net/go/db/exec"
"git.fsdpf.net/go/db/exp"
"git.fsdpf.net/go/db/internal/errors"
"git.fsdpf.net/go/db/internal/sb"
)
var ErrBadFromArgument = errors.New("unsupported DeleteDataset#From argument, a string or identifier expression is required")
type DeleteDataset struct {
dialect SQLDialect
clauses exp.DeleteClauses
isPrepared prepared
queryFactory exec.QueryFactory
err error
hooks exec.Hooks
}
// used internally by database to create a database with a specific adapter
func newDeleteDataset(d string, queryFactory exec.QueryFactory) *DeleteDataset {
return &DeleteDataset{
clauses: exp.NewDeleteClauses(),
dialect: GetDialect(d),
queryFactory: queryFactory,
isPrepared: preparedNoPreference,
err: nil,
}
}
func Delete(table interface{}) *DeleteDataset {
return newDeleteDataset("default", nil).From(table)
}
func (dd *DeleteDataset) Expression() exp.Expression {
return dd
}
// Clones the dataset
func (dd *DeleteDataset) Clone() exp.Expression {
return dd.copy(dd.clauses)
}
// Set the parameter interpolation behavior. See examples
//
// prepared: If true the dataset WILL NOT interpolate the parameters.
func (dd *DeleteDataset) Prepared(prepared bool) *DeleteDataset {
ret := dd.copy(dd.clauses)
ret.isPrepared = preparedFromBool(prepared)
return ret
}
// Returns true if Prepared(true) has been called on this dataset
func (dd *DeleteDataset) IsPrepared() bool {
return dd.isPrepared.Bool()
}
// Sets the adapter used to serialize values and create the SQL statement
func (dd *DeleteDataset) WithDialect(dl string) *DeleteDataset {
ds := dd.copy(dd.GetClauses())
ds.dialect = GetDialect(dl)
return ds
}
// Returns the current SQLDialect on the dataset
func (dd *DeleteDataset) Dialect() SQLDialect {
return dd.dialect
}
// Set the dialect for this dataset.
func (dd *DeleteDataset) SetDialect(dialect SQLDialect) *DeleteDataset {
cd := dd.copy(dd.GetClauses())
cd.dialect = dialect
return cd
}
// Returns the current clauses on the dataset.
func (dd *DeleteDataset) GetClauses() exp.DeleteClauses {
return dd.clauses
}
// used interally to copy the dataset
func (dd *DeleteDataset) copy(clauses exp.DeleteClauses) *DeleteDataset {
return &DeleteDataset{
dialect: dd.dialect,
clauses: clauses,
isPrepared: dd.isPrepared,
queryFactory: dd.queryFactory,
err: dd.err,
hooks: dd.hooks,
}
}
// Creates a WITH clause for a common table expression (CTE).
//
// The name will be available to SELECT from in the associated query; and can optionally
// contain a list of column names "name(col1, col2, col3)".
//
// The name will refer to the results of the specified subquery.
func (dd *DeleteDataset) With(name string, subquery exp.Expression) *DeleteDataset {
return dd.copy(dd.clauses.CommonTablesAppend(exp.NewCommonTableExpression(false, name, subquery)))
}
// Creates a WITH RECURSIVE clause for a common table expression (CTE)
//
// The name will be available to SELECT from in the associated query; and must
// contain a list of column names "name(col1, col2, col3)" for a recursive clause.
//
// The name will refer to the results of the specified subquery. The subquery for
// a recursive query will always end with a UNION or UNION ALL with a clause that
// refers to the CTE by name.
func (dd *DeleteDataset) WithRecursive(name string, subquery exp.Expression) *DeleteDataset {
return dd.copy(dd.clauses.CommonTablesAppend(exp.NewCommonTableExpression(true, name, subquery)))
}
// Adds a FROM clause. This return a new dataset with the original sources replaced. See examples.
// You can pass in the following.
//
// string: Will automatically be turned into an identifier
// Dataset: Will be added as a sub select. If the Dataset is not aliased it will automatically be aliased
// LiteralExpression: (See Literal) Will use the literal SQL
func (dd *DeleteDataset) From(table interface{}) *DeleteDataset {
return dd.copy(dd.clauses.SetFrom(exp.NewColumnListExpression(table)))
// switch t := table.(type) {
// case exp.IdentifierExpression:
// return dd.copy(dd.clauses.SetFrom(t))
// case string:
// return dd.copy(dd.clauses.SetFrom(exp.ParseIdentifier(t)))
// default:
// panic(ErrBadFromArgument)
// }
}
// Adds a WHERE clause. See examples.
func (dd *DeleteDataset) Where(expressions ...exp.Expression) *DeleteDataset {
return dd.copy(dd.clauses.WhereAppend(expressions...))
}
// Removes the WHERE clause. See examples.
func (dd *DeleteDataset) ClearWhere() *DeleteDataset {
return dd.copy(dd.clauses.ClearWhere())
}
// Adds a ORDER clause. If the ORDER is currently set it replaces it. See examples.
func (dd *DeleteDataset) Order(order ...exp.OrderedExpression) *DeleteDataset {
return dd.copy(dd.clauses.SetOrder(order...))
}
// Adds a more columns to the current ORDER BY clause. If no order has be previously specified it is the same as
// calling Order. See examples.
func (dd *DeleteDataset) OrderAppend(order ...exp.OrderedExpression) *DeleteDataset {
return dd.copy(dd.clauses.OrderAppend(order...))
}
// Adds a more columns to the beginning of the current ORDER BY clause. If no order has be previously specified it is the same as
// calling Order. See examples.
func (dd *DeleteDataset) OrderPrepend(order ...exp.OrderedExpression) *DeleteDataset {
return dd.copy(dd.clauses.OrderPrepend(order...))
}
// Removes the ORDER BY clause. See examples.
func (dd *DeleteDataset) ClearOrder() *DeleteDataset {
return dd.copy(dd.clauses.ClearOrder())
}
// Adds a LIMIT clause. If the LIMIT is currently set it replaces it. See examples.
func (dd *DeleteDataset) Limit(limit uint) *DeleteDataset {
if limit > 0 {
return dd.copy(dd.clauses.SetLimit(limit))
}
return dd.copy(dd.clauses.ClearLimit())
}
// Adds a LIMIT ALL clause. If the LIMIT is currently set it replaces it. See examples.
func (dd *DeleteDataset) LimitAll() *DeleteDataset {
return dd.copy(dd.clauses.SetLimit(L("ALL")))
}
// Removes the LIMIT clause.
func (dd *DeleteDataset) ClearLimit() *DeleteDataset {
return dd.copy(dd.clauses.ClearLimit())
}
// Adds a RETURNING clause to the dataset if the adapter supports it.
func (dd *DeleteDataset) Returning(returning ...interface{}) *DeleteDataset {
return dd.copy(dd.clauses.SetReturning(exp.NewColumnListExpression(returning...)))
}
// Get any error that has been set or nil if no error has been set.
func (dd *DeleteDataset) Error() error {
return dd.err
}
// Set an error on the dataset if one has not already been set. This error will be returned by a future call to Error
// or as part of ToSQL. This can be used by end users to record errors while building up queries without having to
// track those separately.
func (dd *DeleteDataset) SetError(err error) *DeleteDataset {
if dd.err == nil {
dd.err = err
}
return dd
}
// Generates a DELETE sql statement, if Prepared has been called with true then the parameters will not be interpolated.
// See examples.
//
// Errors:
// - There is an error generating the SQL
func (dd *DeleteDataset) ToSQL() (sql string, params []interface{}, err error) {
return dd.deleteSQLBuilder().ToSQL()
}
// Appends this Dataset's DELETE statement to the SQLBuilder
// This is used internally when using deletes in CTEs
func (dd *DeleteDataset) AppendSQL(b sb.SQLBuilder) {
if dd.err != nil {
b.SetError(dd.err)
return
}
dd.dialect.ToDeleteSQL(b, dd.GetClauses())
}
func (dd *DeleteDataset) GetAs() exp.IdentifierExpression {
return nil
}
func (dd *DeleteDataset) ReturnsColumns() bool {
return dd.clauses.HasReturning()
}
// Creates an QueryExecutor to execute the query.
//
// db.Delete("test").Exec()
//
// See Dataset#ToUpdateSQL for arguments
func (dd *DeleteDataset) Executor() (executor exec.QueryExecutor) {
if dd.hooks != nil {
dd.SetError(dd.hooks.Before(dd))
}
executor = dd.queryFactory.FromSQLBuilder(dd.deleteSQLBuilder())
if dd.hooks != nil {
executor.Hook(func(result interface{}) error {
return dd.hooks.After(dd, result)
})
}
return executor
}
func (dd *DeleteDataset) deleteSQLBuilder() sb.SQLBuilder {
buf := sb.NewSQLBuilder(dd.isPrepared.Bool())
if dd.err != nil {
return buf.SetError(dd.err)
}
dd.dialect.ToDeleteSQL(buf, dd.clauses)
return buf
}