...

Source file src/github.com/doug-martin/goqu/v9/insert_dataset.go

Documentation: github.com/doug-martin/goqu/v9

     1  package goqu
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/doug-martin/goqu/v9/exec"
     7  	"github.com/doug-martin/goqu/v9/exp"
     8  	"github.com/doug-martin/goqu/v9/internal/errors"
     9  	"github.com/doug-martin/goqu/v9/internal/sb"
    10  )
    11  
    12  type InsertDataset struct {
    13  	dialect      SQLDialect
    14  	clauses      exp.InsertClauses
    15  	isPrepared   prepared
    16  	queryFactory exec.QueryFactory
    17  	err          error
    18  }
    19  
    20  var ErrUnsupportedIntoType = errors.New("unsupported table type, a string or identifier expression is required")
    21  
    22  // used internally by database to create a database with a specific adapter
    23  func newInsertDataset(d string, queryFactory exec.QueryFactory) *InsertDataset {
    24  	return &InsertDataset{
    25  		clauses:      exp.NewInsertClauses(),
    26  		dialect:      GetDialect(d),
    27  		queryFactory: queryFactory,
    28  	}
    29  }
    30  
    31  // Creates a new InsertDataset for the provided table. Using this method will only allow you
    32  // to create SQL user Database#From to create an InsertDataset with query capabilities
    33  func Insert(table interface{}) *InsertDataset {
    34  	return newInsertDataset("default", nil).Into(table)
    35  }
    36  
    37  // Set the parameter interpolation behavior. See examples
    38  //
    39  // prepared: If true the dataset WILL NOT interpolate the parameters.
    40  func (id *InsertDataset) Prepared(prepared bool) *InsertDataset {
    41  	ret := id.copy(id.clauses)
    42  	ret.isPrepared = preparedFromBool(prepared)
    43  	return ret
    44  }
    45  
    46  func (id *InsertDataset) IsPrepared() bool {
    47  	return id.isPrepared.Bool()
    48  }
    49  
    50  // Sets the adapter used to serialize values and create the SQL statement
    51  func (id *InsertDataset) WithDialect(dl string) *InsertDataset {
    52  	ds := id.copy(id.GetClauses())
    53  	ds.dialect = GetDialect(dl)
    54  	return ds
    55  }
    56  
    57  // Returns the current adapter on the dataset
    58  func (id *InsertDataset) Dialect() SQLDialect {
    59  	return id.dialect
    60  }
    61  
    62  // Returns the current adapter on the dataset
    63  func (id *InsertDataset) SetDialect(dialect SQLDialect) *InsertDataset {
    64  	cd := id.copy(id.GetClauses())
    65  	cd.dialect = dialect
    66  	return cd
    67  }
    68  
    69  func (id *InsertDataset) Expression() exp.Expression {
    70  	return id
    71  }
    72  
    73  // Clones the dataset
    74  func (id *InsertDataset) Clone() exp.Expression {
    75  	return id.copy(id.clauses)
    76  }
    77  
    78  // Returns the current clauses on the dataset.
    79  func (id *InsertDataset) GetClauses() exp.InsertClauses {
    80  	return id.clauses
    81  }
    82  
    83  // used interally to copy the dataset
    84  func (id *InsertDataset) copy(clauses exp.InsertClauses) *InsertDataset {
    85  	return &InsertDataset{
    86  		dialect:      id.dialect,
    87  		clauses:      clauses,
    88  		isPrepared:   id.isPrepared,
    89  		queryFactory: id.queryFactory,
    90  		err:          id.err,
    91  	}
    92  }
    93  
    94  // Creates a WITH clause for a common table expression (CTE).
    95  //
    96  // The name will be available to SELECT from in the associated query; and can optionally
    97  // contain a list of column names "name(col1, col2, col3)".
    98  //
    99  // The name will refer to the results of the specified subquery.
   100  func (id *InsertDataset) With(name string, subquery exp.Expression) *InsertDataset {
   101  	return id.copy(id.clauses.CommonTablesAppend(exp.NewCommonTableExpression(false, name, subquery)))
   102  }
   103  
   104  // Creates a WITH RECURSIVE clause for a common table expression (CTE)
   105  //
   106  // The name will be available to SELECT from in the associated query; and must
   107  // contain a list of column names "name(col1, col2, col3)" for a recursive clause.
   108  //
   109  // The name will refer to the results of the specified subquery. The subquery for
   110  // a recursive query will always end with a UNION or UNION ALL with a clause that
   111  // refers to the CTE by name.
   112  func (id *InsertDataset) WithRecursive(name string, subquery exp.Expression) *InsertDataset {
   113  	return id.copy(id.clauses.CommonTablesAppend(exp.NewCommonTableExpression(true, name, subquery)))
   114  }
   115  
   116  // Sets the table to insert INTO. This return a new dataset with the original table replaced. See examples.
   117  // You can pass in the following.
   118  //   string: Will automatically be turned into an identifier
   119  //   Expression: Any valid expression (IdentifierExpression, AliasedExpression, Literal, etc.)
   120  func (id *InsertDataset) Into(into interface{}) *InsertDataset {
   121  	switch t := into.(type) {
   122  	case exp.Expression:
   123  		return id.copy(id.clauses.SetInto(t))
   124  	case string:
   125  		return id.copy(id.clauses.SetInto(exp.ParseIdentifier(t)))
   126  	default:
   127  		panic(ErrUnsupportedIntoType)
   128  	}
   129  }
   130  
   131  // Sets the Columns to insert into
   132  func (id *InsertDataset) Cols(cols ...interface{}) *InsertDataset {
   133  	return id.copy(id.clauses.SetCols(exp.NewColumnListExpression(cols...)))
   134  }
   135  
   136  // Clears the Columns to insert into
   137  func (id *InsertDataset) ClearCols() *InsertDataset {
   138  	return id.copy(id.clauses.SetCols(nil))
   139  }
   140  
   141  // Adds columns to the current list of columns clause. See examples
   142  func (id *InsertDataset) ColsAppend(cols ...interface{}) *InsertDataset {
   143  	return id.copy(id.clauses.ColsAppend(exp.NewColumnListExpression(cols...)))
   144  }
   145  
   146  // Adds a subquery to the insert. See examples.
   147  func (id *InsertDataset) FromQuery(from exp.AppendableExpression) *InsertDataset {
   148  	if sds, ok := from.(*SelectDataset); ok {
   149  		if sds.dialect != GetDialect("default") && id.Dialect() != sds.dialect {
   150  			panic(
   151  				fmt.Errorf(
   152  					"incompatible dialects for INSERT (%q) and SELECT (%q)",
   153  					id.dialect.Dialect(), sds.dialect.Dialect(),
   154  				),
   155  			)
   156  		}
   157  		sds.dialect = id.dialect
   158  	}
   159  	return id.copy(id.clauses.SetFrom(from))
   160  }
   161  
   162  // Manually set values to insert See examples.
   163  func (id *InsertDataset) Vals(vals ...[]interface{}) *InsertDataset {
   164  	return id.copy(id.clauses.ValsAppend(vals))
   165  }
   166  
   167  // Clears the values. See examples.
   168  func (id *InsertDataset) ClearVals() *InsertDataset {
   169  	return id.copy(id.clauses.SetVals(nil))
   170  }
   171  
   172  // Insert rows. Rows can be a map, goqu.Record or struct. See examples.
   173  func (id *InsertDataset) Rows(rows ...interface{}) *InsertDataset {
   174  	return id.copy(id.clauses.SetRows(rows))
   175  }
   176  
   177  // Clears the rows for this insert dataset. See examples.
   178  func (id *InsertDataset) ClearRows() *InsertDataset {
   179  	return id.copy(id.clauses.SetRows(nil))
   180  }
   181  
   182  // Adds a RETURNING clause to the dataset if the adapter supports it See examples.
   183  func (id *InsertDataset) Returning(returning ...interface{}) *InsertDataset {
   184  	return id.copy(id.clauses.SetReturning(exp.NewColumnListExpression(returning...)))
   185  }
   186  
   187  // Adds an (ON CONFLICT/ON DUPLICATE KEY) clause to the dataset if the dialect supports it. See examples.
   188  func (id *InsertDataset) OnConflict(conflict exp.ConflictExpression) *InsertDataset {
   189  	return id.copy(id.clauses.SetOnConflict(conflict))
   190  }
   191  
   192  // Clears the on conflict clause. See example
   193  func (id *InsertDataset) ClearOnConflict() *InsertDataset {
   194  	return id.OnConflict(nil)
   195  }
   196  
   197  // Get any error that has been set or nil if no error has been set.
   198  func (id *InsertDataset) Error() error {
   199  	return id.err
   200  }
   201  
   202  // Set an error on the dataset if one has not already been set. This error will be returned by a future call to Error
   203  // or as part of ToSQL. This can be used by end users to record errors while building up queries without having to
   204  // track those separately.
   205  func (id *InsertDataset) SetError(err error) *InsertDataset {
   206  	if id.err == nil {
   207  		id.err = err
   208  	}
   209  
   210  	return id
   211  }
   212  
   213  // Generates the default INSERT statement. If Prepared has been called with true then the statement will not be
   214  // interpolated. See examples. When using structs you may specify a column to be skipped in the insert, (e.g. id) by
   215  // specifying a goqu tag with `skipinsert`
   216  //    type Item struct{
   217  //       Id   uint32 `db:"id" goqu:"skipinsert"`
   218  //       Name string `db:"name"`
   219  //    }
   220  //
   221  // rows: variable number arguments of either map[string]interface, Record, struct, or a single slice argument of the
   222  // accepted types.
   223  //
   224  // Errors:
   225  //  * There is no INTO clause
   226  //  * Different row types passed in, all rows must be of the same type
   227  //  * Maps with different numbers of K/V pairs
   228  //  * Rows of different lengths, (i.e. (Record{"name": "a"}, Record{"name": "a", "age": 10})
   229  //  * Error generating SQL
   230  func (id *InsertDataset) ToSQL() (sql string, params []interface{}, err error) {
   231  	return id.insertSQLBuilder().ToSQL()
   232  }
   233  
   234  // Appends this Dataset's INSERT statement to the SQLBuilder
   235  // This is used internally when using inserts in CTEs
   236  func (id *InsertDataset) AppendSQL(b sb.SQLBuilder) {
   237  	if id.err != nil {
   238  		b.SetError(id.err)
   239  		return
   240  	}
   241  	id.dialect.ToInsertSQL(b, id.GetClauses())
   242  }
   243  
   244  func (id *InsertDataset) GetAs() exp.IdentifierExpression {
   245  	return id.clauses.Alias()
   246  }
   247  
   248  // Sets the alias for this dataset. This is typically used when using a Dataset as MySQL upsert
   249  func (id *InsertDataset) As(alias string) *InsertDataset {
   250  	return id.copy(id.clauses.SetAlias(T(alias)))
   251  }
   252  
   253  func (id *InsertDataset) ReturnsColumns() bool {
   254  	return id.clauses.HasReturning()
   255  }
   256  
   257  // Generates the INSERT sql, and returns an QueryExecutor struct with the sql set to the INSERT statement
   258  //    db.Insert("test").Rows(Record{"name":"Bob"}).Executor().Exec()
   259  //
   260  func (id *InsertDataset) Executor() exec.QueryExecutor {
   261  	return id.queryFactory.FromSQLBuilder(id.insertSQLBuilder())
   262  }
   263  
   264  func (id *InsertDataset) insertSQLBuilder() sb.SQLBuilder {
   265  	buf := sb.NewSQLBuilder(id.isPrepared.Bool())
   266  	if id.err != nil {
   267  		return buf.SetError(id.err)
   268  	}
   269  	id.dialect.ToInsertSQL(buf, id.clauses)
   270  	return buf
   271  }
   272  

View as plain text