Documentation
¶
Overview ¶
Package sqldata was an experiment in connecting SQL queries with Go data structures.
This packages is FROZEN and should probably not be used in new work. Everything here is functional, but after using this system in production for two years, I see too many warts. The template language is too specialized and too difficult to extend. The SQLer concept is not quite right.
On the other hand, I like using this package better than any other database access method I've used – in Go or otherwise. I just think it needs another iteration. I have much of the design of the next iteration done, but I haven't had time to finish implementing it yet. It will not be API-compatible with this package.
I do not intend to make any further changes to this package. When I have the replacement ready, I'll reference it here. If anyone besides me is using this, please contact me.
Original documentation ¶
This package provides a simple query template language and a custom kind of prepared statement to make it easier to read and write structured data in an SQL database. SQL is a rich query language, and this package does not attempt to replace or hide it. Its intent is to provide the flexibility and efficiency of hand-written queries, while eliminating much of the tedium of using data structures in queries and keeping the queries synchronized with the data structures.
Query templates consist of literal SQL interspersed with template actions, which are delimited by "{{" and "}}". Template actions allow the query to depend on the types of the query parameters and result data structure. Non-prepared statements may also depend on parameter values using the getSQL construct described below.
Here is a trivial example that retrieves a single record by ID:
type Person struct { ID int64 Name string City string State string } var Person p err := sqldata.QueryRow(db, `select {{.}} from Persons where ID={{$1}}`, &p, 5) if err != nil { panic(err) }
Actions ¶
Here is the list of actions. "Receivers" and "parameters" are evaluations of data defined in detail below.
{{receiver}} The field expressions generated by the receiver are inserted into the query, separated by commas. The result scanner is prepared to receive values for each field. {{receiver tableAlias}} As {{receiver}} above, but the given table alias is prepended to column names. E.g. if {{.Foo}} would insert "ID, Name", then {{.Foo t}} will insert "t.ID, t.Name". {{receiver "SQL expression"}} Instead of evaluating the receiver type for field expressions as normal, the given literal SQL expression is inserted into the query and the receiver is used as a single destination when scanning result rows. {{exprs receiver}} {{exprs receiver alias}} {{exprs receiver alias "SQL expression"}} These work exactly as their corresponding non-expr versions above, except that they do not affect the expected result columns. This is particularly useful for UNION queries where the receiver fields may need to be referenced in each SELECT, but the number of result columns is established by the first. {{table.column}} Only valid in sqldataExpr struct tags. Marks a table column reference so that a supplied table alias may be used with the expression. E.g. if the tag is `sum({{table.Price}})` and the column is used with a table alias of "p", then the query will contain "sum(p.Price)". See the sqldataExpr example below. {{parameter}} A replacable parameter is put into the query at this point, which will reference the given parameter's value when the query is run. {{values parameter}} A comma-separated list of replacable parameters is put into the query at this point, one for each non-excluded field in the parameter. {{keyValues parameter}} As {{values parameter}} above but only includes fields marked as key values in their sqldata struct tag. {{nonKeyValues parameter}} As {{values parameter}} above but only includes fields not marked as key values in their sqldata struct tag. {{names parameter}} A comma-separated list of the names of non-excluded fields in the parameter is put into the query at this point. {{keyNames parameter}} As {{names parameter}} above but only includes fields marked as key values in their sqldata struct tag. {{nonKeyNames parameter}} As {{names parameter}} above but only includes fields not marked as key values in their sqldata struct tag. {{names=values parameter}} A comma-separated list of names and replacable parameters is put into the query at this point, one for each non-excluded field in the parameter. E.g. if the parameter has fields "ID" and "Name", then the query will include "ID=?, Name=?" or the equivalent for the current SQL dialect. {{keyNames=values parameter}} As {{names=values parameter}} above but only includes fields marked as key values in their sqldata struct tag. {{nonKeyNames=values parameter}} As {{names=values parameter}} above but only includes fields not marked as key values in their sqldata struct tag. {{$alias := $number}} An alias, which must be alphanumeric, is created to reference the given parameter number. Later in the query, $alias may be used instead $number. {{$alias := shift}} This is equivalent to {{$alias := $1}}, except that it shifts the meaning of the parameter numbers used later in the query. $1 will now refer to what was $2, $2 to what was $3, etc. Shifts do not affect which parameter is referenced by previously established aliases. {{dialect "name" ...}} T1 {{end}} If the current dialect name is equal to one of the quoted strings, include T1 in the query. {{dialect "name" ...}} T1 {{else}} T0 {{end}} If the current dialect name is equal to one of the quoted strings, include T1 in the query. Otherwise, include T0. {{dialect "name" ...}} T1 {{else dialect "name" ...}} T0 {{end}} This is a more concise equivalent to writing {{dialect "name" ...}} T1 {{else}}{{dialect "name" ...}} T0 {{end}}{{end}} Any number of {{else dialect}} clauses may be included, followed by an optional {{else}} clause. {{getSQL parameter}} Only valid in non-prepared statements. The given parameter must implement the SQLer interface. Its SQL method is called and the resulting SQL text and parameters are inserted into the query.
Receivers ¶
Receivers are used to specify how result rows are scanned into the destination. A receiver turns the destination type (or the type of a struct field within the destination) into a list of fields, each with an SQL expression and single-field scan destination. These expressions and destinations are used in the query as described under Actions above.
Receivers may take one of the following forms.
- The character '.' (period). In this case, the destination type itself is used as the receiver.
- The name of a field of the destination type, which must be a struct, preceded by a period, such as .Field In this case, the field is used as the receiver. Field references may be chained: .Field1.Field2
Pointers within the destination are dereferenced as needed. If the receiver type is a database/sql/driver.Value or implements the database/sql.Scanner interface, it is treated as a single field. Otherwise, the receiver must be of struct type, and its fields are used as the receiver fields.
Struct fields may be excluded from automatic use as receiver fields by setting their name to "-" using the sqldata struct tag (see below). They may still be used with an explicit SQL expression in the query template.
The field expression is one of the following, in order of preference:
- The value of the field's sqldataExpr struct tag.
- The field's name as set in its sqldata struct tag.
- The field's name in the struct.
When the destination type is used directly as a single-value receiver, there is no struct field from which to derive an expression. In that case, an explicit expression must be provided as in `{{. "expression"}}`.
In a query that produces result rows, there must be a receiver field corresponding to each result column. Otherwise, scanning will result in an error.
Parameters ¶
Parameters reference values in the arguments provided to the query. A parameter starts with the character '$' and a number. The number is the 1-based index of the argument being referenced; e.g. "$3" to reference the third argument. After the number, the parameter may include any number of field references consisting of a '.' character followed by the name of a field of the argument type, which must be a struct; e.g. "$1.Person.ID". Pointers are automatically dereferenced as needed.
No replacement parameters may be included in the query, except through template parameters.
Struct Tags ¶
Package sqldata examines two struct tags: sqldata and sqldataExpr.
The sqldata tag is a comma-separated list of name and options much like that used by encoding/json. A name of "-" excludes the field from automatic use as a receiver field and by the names and values parameter constructs. The only option is "key" which specifies that the field is part of a table's primary key and interacts with several of the parameter actions above.
The sqldataExpr tag specifies an SQL expression to be used instead of the field's name when the field acts as a receiver. This expression may include the {{table.column}} action described above.
Here are a few examples:
// Field is (mostly) ignored by this package. Field int `sqldata:"-"` // Field is stored in the database as "some_name". Field int `sqldata:"some_name"` // Field is stored as Field and is a key. Field int `sqldata:",key"` // Field is stored as some_name but retrieved using an expression. Field int `sqldata:"some_name" sqldataExpr:"count({{table.Value}})"`
Example (Basic) ¶
package main import ( "database/sql" "fmt" "log" "github.com/mstetson/sqldata" _ "github.com/mattn/go-sqlite3" ) var db *sql.DB func init() { var err error db, err = sql.Open("sqlite3", ":memory:") if err != nil { log.Fatal(err) } e := &errExec{q: db} e.Exec(` create table Persons ( ID integer not null primary key, Name text not null, City text not null, State text not null ) `) e.Exec(`insert into Persons (ID, Name, City, State) values (1, "Bilbo", "The Hill", "The Shire"), (2, "Bombur", "Under the Mountain", "Lonely Mountain"), (3, "Beorn", "Carrock", "Wilderland"), (4, "Bard", "Dale", "Desolation of Smaug")`) if e.err != nil { log.Fatal(e.err) } } type errExec struct { q sqldata.Queryer err error } func (e *errExec) Exec(query string, args ...interface{}) { if e.err != nil { return } _, e.err = sqldata.Exec(e.q, query, args...) } func main() { // A Person represents a row from the Persons table in the database. type Person struct { ID int64 Name string City string State string } // The {{}} notation allows the query writer to insert field expressions // and placeholders based on input and output parameter types. var ( personByID, _ = sqldata.Prepare(db, `select {{.}} from Persons where ID={{$1}}`, Person{}, int64(0)) peopleNamedLike, _ = sqldata.Prepare(db, `select {{.}} from Persons where Name like {{$1}}`, Person{}, "") insertPerson, _ = sqldata.Prepare(db, `insert into Persons ({{names $1}}) values ({{values $1}})`, nil, Person{}) updatePerson, _ = sqldata.Prepare(db, `update Persons set {{names=values $2}} where ID={{$1}}`, nil, int64(0), Person{}) ) var err error var p Person var ps []Person // Insert a Person _, err = insertPerson.Exec(Person{5, "William The Conqueror", "London", "England"}) if err != nil { log.Fatal(err) } // Load the Person with ID 5. err = personByID.QueryRow(5).Scan(&p) if err != nil { log.Fatal(err) } fmt.Println(p.Name, "has ID", p.ID) // Load a slice of Persons whose name starts with "william". // QueryAll scans all result rows into a slice. err = peopleNamedLike.QueryAll("william%").Scan(&ps) if err != nil { log.Fatal(err) } fmt.Println("People named William:", len(ps)) // Change William's primary key. oldID := p.ID p.ID = 1066 _, err = updatePerson.Exec(oldID, p) if err != nil { log.Fatal(err) } }
Output: William The Conqueror has ID 5 People named William: 1
Example (SqldataExpr) ¶
package main import ( "database/sql" "time" "github.com/mstetson/sqldata" _ "github.com/mattn/go-sqlite3" ) var db *sql.DB func main() { // First, some structures for our tables. // A Person represents a row from the Persons table in the database. type Person struct { ID int64 Name string City string State string } // A Post represents a row from the Posts table in our database. type Post struct { ID int64 PersonID int64 // This Post was made by the Person with this ID. PostDate time.Time Content string } // PostSummary represents aggregate information about a group of Posts. // Note the use of sqldataExpr to specify the aggregate functions we want. type PostSummary struct { TotalPosts int `sqldataExpr:"count({{table.ID}})"` LastPostDate time.Time `sqldataExpr:"max({{table.PostDate}})"` } // This will get the summary info for all Posts in the database. globalSummaryLoader, _ := sqldata.Prepare(db, `select {{.}} from Posts`, PostSummary{}) defer globalSummaryLoader.Close() // Now we want the same summary data grouped by person. type PersonWithSummary struct { Person PostSummary } personSummaryLoader, _ := sqldata.Prepare(db, `select {{.Person p}}, {{.PostSummary s}} from Persons p join Posts s on (s.PersonID=p.ID) group by {{.Person p}} order by {{.PostSummary.LastPostDate s}} desc`, PersonWithSummary{}) defer personSummaryLoader.Close() // And the same summary data with a different grouping. type PostsByWeekday struct { Weekday int PostSummary } postsByWeekdayLoader, _ := sqldata.Prepare(db, `select {{.Weekday "weekday(PostDate)"}}, {{.PostSummary}} from Posts group by weekday(PostDate)`, PostsByWeekday{}) defer postsByWeekdayLoader.Close() }
Index ¶
- Variables
- func ErrorLocation(e error) (file string, line int)
- func Exec(db Queryer, query string, args ...interface{}) (sql.Result, error)
- func ParameterDollarN(n int) string
- func ParameterQuestion(_ int) string
- func QueryAll(db Queryer, query string, dest interface{}, args ...interface{}) error
- func QueryRow(db Queryer, query string, dest interface{}, args ...interface{}) error
- func RelocateError(e error) error
- func RelocateErrorTo(e error, file string, line int) error
- func StandardQuoteIdentifier(s string) string
- func StandardQuoteString(s string) string
- type AllRows
- type AtInit
- type ContextQueryer
- type Dialect
- func (d *Dialect) Exec(db Queryer, query string, args ...interface{}) (sql.Result, error)
- func (d *Dialect) Prepare(db Queryer, query string, resultType interface{}, argTypes ...interface{}) (*Stmt, error)
- func (d *Dialect) Query(db Queryer, query string, resultType interface{}, args ...interface{}) (*Rows, error)
- func (d *Dialect) QueryAll(db Queryer, query string, dest interface{}, args ...interface{}) error
- func (d *Dialect) QueryRow(db Queryer, query string, dest interface{}, args ...interface{}) error
- type Int64Values
- type ListValues
- type ParamMarker
- type Queryer
- type Row
- type Rows
- type SQLer
- type Stmt
- type TupleKeyValues
- type TupleNonKeyValues
- type TupleValues
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultDialect = &Dialect{ Name: "default", QuoteString: StandardQuoteString, QuoteIdentifier: StandardQuoteIdentifier, Parameter: ParameterQuestion, }
DefaultDialect is the default Dialect used by Prepare, Exec, Query, QueryRow, and QueryAll.
Functions ¶
func ErrorLocation ¶
ErrorLocation returns the source location of an error produced by this package. If the location is unknown or the error was not produced by this package, it returns "unknown", 0.
func Exec ¶
Exec executes a statement with the given arguments and returns an sql.Result summarizing the effect of the statement.
Exec is a wrapper around DefaultDialect.Exec.
func ParameterDollarN ¶
ParameterDollarN returns "$n" where n is the decimal value of n. It is intended for use in Dialects.
func ParameterQuestion ¶
ParameterQuestion returns "?". It is intended for use in Dialects.
func QueryAll ¶
QueryAll is like Query, but retrieves all result rows and appends them to dest, which must be a slice.
Note that there is no need for a separate Scan method, since the destination must be specified for query generation.
QueryAll is a wrapper around DefaultDialect.QueryAll.
Example ¶
package main import ( "database/sql" "fmt" "log" "github.com/mstetson/sqldata" _ "github.com/mattn/go-sqlite3" ) var db *sql.DB func main() { // A Person represents a row from the Persons table in the database. type Person struct { ID int64 Name string City string State string } var ps []Person err := sqldata.QueryAll(db, `select {{.}} from Persons where ID < 5 order by ID`, &ps) if err != nil { log.Fatal(err) } for i := range ps { fmt.Println(ps[i].Name) } }
Output: Bilbo Bombur Beorn Bard
func QueryRow ¶
QueryRow is like Query, but it scans the first result row into dest. If the query returns no rows, QueryRow returns sql.ErrNoRows. Any result rows beyond the first are ignored.
Note that there is no need for a separate Scan method, since the destination must be specified for query generation.
QueryRow is a wrapper around DefaultDialect.QueryRow.
func RelocateError ¶
RelocateError changes the reported source location of an error produced by this package to the site of the caller of the caller of RelocateError. Many of the functions in this package return error values that try to reference the source location of a query template. When wrapping such functions, those references can become incorrect. RelocateError can help.
Error values not produced by this package are returned unchanged.
func RelocateErrorTo ¶
RelocateErrorTo changes the reported source location of an error produced by this package to the given file and line number. Many of the functions in this package return error values that try to reference the source location of a query template. When wrapping such functions, those references can become incorrect. RelocateErrorTo can help.
Error values not produced by this package are returned unchanged.
func StandardQuoteIdentifier ¶
StandardQuoteIdentifier returns s enclosed in double quote characters with any embedded double quotes replaced by a pair of double quotes. It is assumed that the SQL implementation can handle arbitraray UTF-8 in quoted identifiers.
func StandardQuoteString ¶
StandardQuoteString returns s enclosed in single quote characters with any embedded single quotes replaced by a pair of single quotes. It is assumed that the SQL implementation can handle arbitraray UTF-8 in string literals.
Types ¶
type AllRows ¶
type AllRows struct {
// contains filtered or unexported fields
}
An AllRows is returned by Stmt.QueryAll. See Stmt.QueryAll and AllRows.Scan.
type AtInit ¶
An AtInit holds things that should be done at program initialization, but not without an open DB and knowledge of the SQL dialect. It's mostly useful for preparing SQL statements.
Example ¶
package main import ( "database/sql" "log" "github.com/mstetson/sqldata" _ "github.com/mattn/go-sqlite3" ) var db *sql.DB func init() { var err error db, err = sql.Open("sqlite3", ":memory:") if err != nil { log.Fatal(err) } e := &errExec{q: db} e.Exec(` create table Persons ( ID integer not null primary key, Name text not null, City text not null, State text not null ) `) e.Exec(`insert into Persons (ID, Name, City, State) values (1, "Bilbo", "The Hill", "The Shire"), (2, "Bombur", "Under the Mountain", "Lonely Mountain"), (3, "Beorn", "Carrock", "Wilderland"), (4, "Bard", "Dale", "Desolation of Smaug")`) if e.err != nil { log.Fatal(e.err) } } type errExec struct { q sqldata.Queryer err error } func (e *errExec) Exec(query string, args ...interface{}) { if e.err != nil { return } _, e.err = sqldata.Exec(e.q, query, args...) } func main() { // Usually, this will be package scoped. var atInit = new(sqldata.AtInit) // Someplace else, declare a type. type Part struct { ID int64 Name string } // And some prepared statements using the type. var ( someRandomQuery = atInit.Prepare( `select {{.}} from Parts where ID={{$1}}`, Part{}, int64(0), ) someOtherQuery = atInit.Prepare( `select {{.}} from Parts where Name like {{$1}}`, Part{}, "", ) ) // Later, open the database and initialize everything. db, err := sql.Open("driver", "dsn") if err != nil { log.Fatal(err) } err = atInit.Init(db) if err != nil { log.Fatal(err) } // Then use the prepared statements. _ = someRandomQuery.QueryRow(5) _ = someOtherQuery.QueryAll("widget") }
func (*AtInit) InitDialect ¶
InitDialect runs each of the functions that have been set to run at init. If any function returns an error, the error is returned and no further functions are called.
type ContextQueryer ¶
type ContextQueryer interface { ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) }
Queryer abstracts sql.DB, sql.Conn, and sql.Tx. It differs from Queryer by using the ...Context methods.
type Dialect ¶
type Dialect struct { // Name gives a name to this dialect for use by the // {{dialect "name"}} construct. Name is free form and // has no particular meaning to this package. Name string // QuoteString returns the properly-quoted string // literal representation of s for use in an SQL query. QuoteString func(s string) string // QuoteIdentifier returns the properly-quoted identifier form // of s for use in an SQL query. Note that the returned // string need not actually be quoted if QuoteIdentifier // determines that quoting is unnecessary. QuoteIdentifier func(s string) string // Parameter returns the string used to mark the nth // replacable parameter in a query. Parameters are // numbered from 1. Parameters are always used in order // in the query and each is only referenced once, so // dialects that can only reference parameters that // way are supported. Parameter func(n int) string }
A Dialect hides some of the differences between implementations of SQL.
func (*Dialect) Exec ¶
Exec executes a statement with the given arguments and returns an sql.Result summarizing the effect of the statement.
func (*Dialect) Prepare ¶
func (d *Dialect) Prepare(db Queryer, query string, resultType interface{}, argTypes ...interface{}) (*Stmt, error)
Prepare creates a Stmt. It parses the query according to the template language defined above and generates SQL based on the given result type and argument types. resultType should have the same type as a single result row, and each argType the type of an argument to be passed to the Stmt's Query or Exec methods. The generated SQL statement is prepared for use with db.
func (*Dialect) Query ¶
func (d *Dialect) Query(db Queryer, query string, resultType interface{}, args ...interface{}) (*Rows, error)
Query parses query according to the template language defined above and executes it on db for the given result type and arguments. Since the argument values are available, the getSQL action may be used in the query.
func (*Dialect) QueryAll ¶
QueryAll is like Query, but retrieves all result rows and appends them to dest, which must be a slice.
Note that there is no need for a separate Scan method, since the destination must be specified for query generation.
func (*Dialect) QueryRow ¶
QueryRow is like Query, but it scans the first result row into dest. If the query returns no rows, QueryRow returns sql.ErrNoRows. Any result rows beyond the first are ignored.
Note that there is no need for a separate Scan method, since the destination must be specified for query generation.
type Int64Values ¶
type Int64Values []int64
Int64Values is an SQLer that produces a parenthesized list of the values in Slice. This is useful for queries like
r, err := sqldata.Query(db, "select {{.}} from Table where ID in {{getSQL $1}}", Person{}, sqldata.Int64Values{1, 2, 3}, )
Have a care about NOT IN and empty lists. Try `IFNULL(foo NOT IN {{getSQL $1}}, TRUE)`.
func (Int64Values) SQL ¶
func (s Int64Values) SQL(_ *Dialect, _ *ParamMarker) (string, []interface{}, error)
type ListValues ¶
type ListValues struct {
Slice interface{}
}
ListValues is an SQLer that produces a parenthesized list of the values in Slice. This is useful for queries like
r, err := sqldata.Query(db, "select {{.}} from Table where ID in {{getSQL $1}}", Person{}, sqldata.ListValues{[]int{1, 2, 3}}, )
Note: If the list is empty, the sql will be "(NULL)". This often will work as expected for "WHERE foo IN (NULL)", but BE CAREFUL! Both "foo IN (NULL)" and "foo NOT IN (NULL)" evaluate to NULL in SQL – neither true nor false.
The problem is that SQL has no syntax for an empty list, and tricks with subqueries like '(select 0 from dual where 0=1)' are database-specific and sometimes problematic. See MySQL bug #44339. Caveat SQLor.
func (ListValues) SQL ¶
func (l ListValues) SQL(d *Dialect, p *ParamMarker) (string, []interface{}, error)
SQL implements the SQLer interface.
type ParamMarker ¶
type ParamMarker struct {
// contains filtered or unexported fields
}
A ParamMarker uses a Dialect to get the replaceable parameter markers for a single query. It is used both internally and by SQLers.
func NewParamMarker ¶
func NewParamMarker(d *Dialect) *ParamMarker
NewParamMarker returns a zeroed ParamMarker that uses Dialect d.
func (*ParamMarker) Next ¶
func (p *ParamMarker) Next() string
Next returns the next parameter marker string for p.
type Queryer ¶
type Queryer interface { Exec(query string, args ...interface{}) (sql.Result, error) Prepare(query string) (*sql.Stmt, error) Query(query string, args ...interface{}) (*sql.Rows, error) }
A Queryer can prepare and execute database/sql queries. It allows methods not to care whether they are called with *sql.DB or *sql.Tx.
func WithContext ¶
func WithContext(ctx context.Context, q ContextQueryer) Queryer
WithContext returns a Queryer that uses q and ctx behind the scenes. This allows adapting existing sqldata code to use context without as much editing.
Where you may have used sqldata.Query(db, query) you now can use sqldata.Query(sqldata.WithContext(ctx, db), query).
type Row ¶
type Row struct {
// contains filtered or unexported fields
}
A Row is returned by Stmt.QueryRow. See Stmt.QueryRow and Row.Scan.
type Rows ¶
type Rows struct {
// contains filtered or unexported fields
}
Rows is a wrapper around sql.Rows which will scan result rows into data structures according to a query template's receiver specifications.
func Query ¶
Query parses query according to the template language defined above and executes it on db for the given result type and arguments. Since the argument values are available, the getSQL action may be used in the query.
Query is a wrapper around DefaultDialect.Query.
func (*Rows) Close ¶
Close closes the Rows, preventing further enumeration. If Next returns false, the Rows are closed automatically and it will suffice to check the result of Err. Close is idempotent and does not affect the result of Err.
func (*Rows) Columns ¶
Columns returns the column names. Columns returns an error if the rows are closed.
func (*Rows) Err ¶
Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
type SQLer ¶
type SQLer interface { // SQL returns a portion of an SQL query along with // argument values for any positional parameters in this // query portion. The Dialect and ParamMarker should be // used to generate the SQL fragment as appropriate. SQL(d *Dialect, p *ParamMarker) (string, []interface{}, error) }
An SQLer has the SQL method. See the {{getSQL}} template action above for more details.
type Stmt ¶
type Stmt struct {
// contains filtered or unexported fields
}
Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
func Prepare ¶
func Prepare(db Queryer, query string, resultType interface{}, argTypes ...interface{}) (*Stmt, error)
Prepare creates a Stmt. It parses the query according to the template language defined above and generates SQL based on the given result type and argument types. resultType should have the same type as a single result row, and each argType the type of an argument to be passed to the Stmt's Query or Exec methods. The generated SQL statement is prepared for use with db.
Prepare is a wrapper around DefaultDialect.Prepare.
func (*Stmt) Exec ¶
Exec executes a prepared statement with the given arguments and returns a sql.Result summarizing the effect of the statement.
func (*Stmt) Query ¶
Query executes a prepared query statement with the given arguments and returns the query results as a *Rows.
The argument types must match those passed to Prepare.
func (*Stmt) QueryAll ¶
QueryAll executes a prepared query statement with the given arguments. If an error occurs during the execution of the statement, that error will be returned by a call to Scan on the returned *AllRows, which is always non-nil.
The argument types must match those passed to Prepare.
func (*Stmt) QueryRow ¶
QueryRow executes a prepared query statement with the given arguments. If an error occurs during the execution of the statement, that error will be returned by a call to Scan on the returned *Row, which is always non-nil. If the query selects no rows, the *Row's Scan will return sql.ErrNoRows. Otherwise, the *Row's Scan scans the first selected row and discards the rest.
The argument types must match those passed to Prepare.
type TupleKeyValues ¶
type TupleKeyValues struct {
Slice interface{}
}
TupleKeyValues is just like TupleValues, except it only uses values that would be selected by the keyValues template function.
func (TupleKeyValues) SQL ¶
func (l TupleKeyValues) SQL(d *Dialect, p *ParamMarker) (string, []interface{}, error)
SQL implements the SQLer interface.
type TupleNonKeyValues ¶
type TupleNonKeyValues struct {
Slice interface{}
}
TupleNonKeyValues is just like TupleValues, except it only uses values that would be selected by the nonKeyValues template function.
func (TupleNonKeyValues) SQL ¶
func (l TupleNonKeyValues) SQL(d *Dialect, p *ParamMarker) (string, []interface{}, error)
SQL implements the SQLer interface.
type TupleValues ¶
type TupleValues struct {
Slice interface{}
}
TupleValues is an SQLer that produces a comma-separated list of parenthesized tuple values. This is useful for multi-record inserts like
r, err := sqldata.Exec(db, "insert into Table ({{names $1}}) values {{getSQL $2}}", Person{}, sqldata.TupleValues{[]Person{p1, p2, p3}}, )
func (TupleValues) SQL ¶
func (l TupleValues) SQL(d *Dialect, p *ParamMarker) (string, []interface{}, error)
SQL implements the SQLer interface.