mirror of
https://github.com/davidallendj/artisan.git
synced 2025-12-20 03:07:00 -07:00
Initial commit
This commit is contained in:
commit
c2e8f78d0c
12 changed files with 502 additions and 0 deletions
3
go.mod
Normal file
3
go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/davidallendj/artisan
|
||||||
|
|
||||||
|
go 1.22.6
|
||||||
45
main.go
Normal file
45
main.go
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
artisan "github.com/davidallendj/artisan/pkg/artisan"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// the builder is always the starting point with artisan
|
||||||
|
var (
|
||||||
|
b = artisan.Builder{}
|
||||||
|
name = "david"
|
||||||
|
count = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// do 'create' with two different ways to add columns
|
||||||
|
fmt.Printf("create.1: %s\n", b.Create("test").WithAttribute(artisan.TABLE).AddColumns(artisan.Columns{
|
||||||
|
"count": artisan.Integer{},
|
||||||
|
"name": artisan.Text{},
|
||||||
|
}).Build())
|
||||||
|
fmt.Printf("create.2: %s\n", b.Create("test").AddColumn("count", artisan.Integer{}).AddColumn("name", artisan.Text{}).Build())
|
||||||
|
fmt.Printf("create.3: %s\n", b.Create("test").AddColumns(artisan.Columns{"count": artisan.Integer{}, "name": artisan.Text{}}).Build())
|
||||||
|
|
||||||
|
// do 'insert' with two different ways to add values
|
||||||
|
fmt.Printf("insert.1: %s\n", b.Insert("test").AddValue("count", count).Build())
|
||||||
|
fmt.Printf("insert.2: %s\n", b.Insert("test").AddValues(artisan.Values{"count": count, "name": name}).Build())
|
||||||
|
|
||||||
|
// do 'select' both with and without 'where' clause
|
||||||
|
fmt.Printf("select.1: %s\n", b.Select().From("test").Where(artisan.IsEqual("name", name)).Build())
|
||||||
|
fmt.Printf("select.2: %s\n", b.Select(artisan.AllColumns()).From("test").Build())
|
||||||
|
fmt.Printf("select.3: %s\n", b.Select("count", "name").From("test").Where("count>10").Build())
|
||||||
|
fmt.Printf("select.4: %s\n", b.Select("name").WithAttribute(artisan.DISTINCT).From("test").Where(artisan.IsGreaterThanOrEqual("count", 10)).Build())
|
||||||
|
|
||||||
|
// do 'update' to set existing values
|
||||||
|
fmt.Printf("update.1: %s\n", b.Update("test").Set(artisan.Values{"count": 10, "name": "joe"}).Where("count>3").Build())
|
||||||
|
fmt.Printf("update.2: %s\n", b.Update("test").Set(artisan.Values{"count": 10, "name": "joe"}).Where(artisan.IsGreaterThan("count", 3)).OrderBy("count").Limit(10).Offset(2).Build())
|
||||||
|
|
||||||
|
// do 'delete' and delete a single and multiple records
|
||||||
|
fmt.Printf("delete.1: %s\n", b.Delete("test").Where(artisan.IsLessThanOrEqual("count", 1)).Build())
|
||||||
|
|
||||||
|
// do 'drop' to remove a table
|
||||||
|
fmt.Printf("drop.1: %s\n", b.Drop("test").Build())
|
||||||
|
fmt.Printf("drop.2: %s\n", b.Drop("test").IfExists().Build())
|
||||||
|
}
|
||||||
54
pkg/artisan/builder.go
Normal file
54
pkg/artisan/builder.go
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sql "github.com/davidallendj/artisan/pkg/artisan/driver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type state interface {
|
||||||
|
GetBuilder() *Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
type Builder struct {
|
||||||
|
Driver sql.Driver
|
||||||
|
stmt string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type fromClause struct{ builder *Builder }
|
||||||
|
type whereClause struct{ builder *Builder }
|
||||||
|
|
||||||
|
type tablename string
|
||||||
|
type conditional string
|
||||||
|
|
||||||
|
func IsGreaterThan[T any, U any](column T, value U) conditional {
|
||||||
|
return conditional(fmt.Sprintf("%v>%v", column, ConvertValue(value)))
|
||||||
|
}
|
||||||
|
func IsGreaterThanOrEqual[T any, U any](column T, value U) conditional {
|
||||||
|
return conditional(fmt.Sprintf("%v>=%v", column, ConvertValue(value)))
|
||||||
|
}
|
||||||
|
func IsLessThan[T any, U any](column T, value U) conditional {
|
||||||
|
return conditional(fmt.Sprintf("%v<%v", column, ConvertValue(value)))
|
||||||
|
}
|
||||||
|
func IsLessThanOrEqual[T any, U any](column T, value U) conditional {
|
||||||
|
return conditional(fmt.Sprintf("%v<=%v", column, ConvertValue(value)))
|
||||||
|
}
|
||||||
|
func IsEqual[T any, U any](column T, value U) conditional {
|
||||||
|
return conditional(fmt.Sprintf("%v=%v", column, ConvertValue(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) Build() string {
|
||||||
|
var s []byte = make([]byte, len(b.stmt))
|
||||||
|
copy(s, b.stmt)
|
||||||
|
b.Reset()
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) Error() error {
|
||||||
|
return b.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) Reset() {
|
||||||
|
b.stmt = ""
|
||||||
|
}
|
||||||
111
pkg/artisan/create.go
Normal file
111
pkg/artisan/create.go
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TABLE createAttribute = iota
|
||||||
|
TRIGGER
|
||||||
|
INDEX
|
||||||
|
VIEW
|
||||||
|
)
|
||||||
|
|
||||||
|
type createAttribute int
|
||||||
|
type createColumns struct {
|
||||||
|
builder *Builder
|
||||||
|
tableName string
|
||||||
|
}
|
||||||
|
type create struct {
|
||||||
|
builder *Builder
|
||||||
|
columns []Column
|
||||||
|
}
|
||||||
|
type createOptions struct {
|
||||||
|
attribute createAttribute
|
||||||
|
}
|
||||||
|
type CreateOption func(*createOptions)
|
||||||
|
|
||||||
|
func getCreateOptions(opts ...CreateOption) *createOptions {
|
||||||
|
co := &createOptions{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(co)
|
||||||
|
}
|
||||||
|
return co
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) Create(tableName string) *createColumns {
|
||||||
|
// always reset string if calling create
|
||||||
|
b.Reset()
|
||||||
|
b.stmt += fmt.Sprintf("CREATE TABLE %s", tableName)
|
||||||
|
|
||||||
|
return &createColumns{builder: b, tableName: tableName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *createColumns) WithAttribute(attribute createAttribute) *createColumns {
|
||||||
|
switch attribute {
|
||||||
|
case TRIGGER:
|
||||||
|
// b.stmt += fmt.Sprintf("CREATE TRIGGER %s")
|
||||||
|
/* TODO */
|
||||||
|
case VIEW:
|
||||||
|
// b.stmt += fmt.Sprintf("CREATE VIEW %s")
|
||||||
|
/* TODO */
|
||||||
|
case INDEX:
|
||||||
|
/* TODO */
|
||||||
|
case TABLE:
|
||||||
|
c.builder.stmt = fmt.Sprintf("CREATE TABLE %s", c.tableName)
|
||||||
|
default:
|
||||||
|
c.builder.stmt = fmt.Sprintf("CREATE TABLE %s", c.tableName)
|
||||||
|
// TODO: do reflection and add to stmt based on *supported* data type
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *createColumns) AddColumn(name string, typ Type) *create {
|
||||||
|
cc := &create{builder: c.builder}
|
||||||
|
return cc.AddColumn(name, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *create) AddColumn(name string, typ Type) *create {
|
||||||
|
c.columns = append(c.columns, Column{name, typ})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *createColumns) AddColumns(columns Columns) *create {
|
||||||
|
cc := &create{builder: c.builder}
|
||||||
|
return cc.AddColumns(columns)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *create) AddColumns(columns Columns) *create {
|
||||||
|
for k, v := range columns {
|
||||||
|
c.columns = append(c.columns, Column{k, v})
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *create) Build() string {
|
||||||
|
var columns, values string
|
||||||
|
for _, col := range c.columns {
|
||||||
|
columns += fmt.Sprintf("%s %s, ", col.Name, col.Type.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim off trailing delimiter
|
||||||
|
columns = strings.TrimRight(columns, ", ")
|
||||||
|
values = strings.TrimRight(values, ", ")
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s(%s);", c.builder.stmt, columns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func WithColumn(name string, _type Type) CreateOption {
|
||||||
|
// return func(co *createOptions) {
|
||||||
|
// co.columns = append(co.columns, Column{name: name, _type: _type})
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func WithColumns(columns Columns) CreateOption {
|
||||||
|
// return func(co *createOptions) {
|
||||||
|
// for name, _type := range columns {
|
||||||
|
// WithColumn(name, _type)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
18
pkg/artisan/delete.go
Normal file
18
pkg/artisan/delete.go
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type deleteClause struct{ builder *Builder }
|
||||||
|
|
||||||
|
func (b *Builder) Delete(tableName string) *deleteClause {
|
||||||
|
b.stmt = fmt.Sprintf("DELETE FROM %s", tableName)
|
||||||
|
return &deleteClause{builder: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *deleteClause) Where(condition conditional) *whereClause {
|
||||||
|
s.builder.stmt += fmt.Sprintf(" WHERE %s", condition)
|
||||||
|
return &whereClause{builder: s.builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
// defined in `select.go`
|
||||||
|
// func (s *whereClause) Build() string
|
||||||
5
pkg/artisan/driver/driver.go
Normal file
5
pkg/artisan/driver/driver.go
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package sql
|
||||||
|
|
||||||
|
type Driver interface {
|
||||||
|
Build() string
|
||||||
|
}
|
||||||
30
pkg/artisan/drop.go
Normal file
30
pkg/artisan/drop.go
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type drop struct {
|
||||||
|
builder *Builder
|
||||||
|
}
|
||||||
|
type dropOptional struct {
|
||||||
|
tableName string
|
||||||
|
builder *Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) Drop(tableName string) *dropOptional {
|
||||||
|
b.Reset()
|
||||||
|
b.stmt += fmt.Sprintf("DROP TABLE %s", tableName)
|
||||||
|
return &dropOptional{builder: b, tableName: tableName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dropOptional) IfExists() *drop {
|
||||||
|
d.builder.stmt = fmt.Sprintf("DROP TABLE IF EXISTS %s", d.tableName)
|
||||||
|
return &drop{builder: d.builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dropOptional) Build() string {
|
||||||
|
return d.builder.stmt + ";"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *drop) Build() string {
|
||||||
|
return d.builder.stmt + ";"
|
||||||
|
}
|
||||||
57
pkg/artisan/insert.go
Normal file
57
pkg/artisan/insert.go
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type insertClause struct {
|
||||||
|
builder *Builder
|
||||||
|
columns []Column
|
||||||
|
}
|
||||||
|
type insertColumns struct {
|
||||||
|
builder *Builder
|
||||||
|
tableName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) Insert(tableName string) *insertColumns {
|
||||||
|
b.Reset()
|
||||||
|
b.stmt += fmt.Sprintf("INSERT INTO %s", tableName)
|
||||||
|
|
||||||
|
return &insertColumns{builder: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *insertColumns) AddValue(name string, value any) *insertClause {
|
||||||
|
ic := &insertClause{builder: i.builder}
|
||||||
|
return ic.AddValue(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *insertClause) AddValue(name string, value any) *insertClause {
|
||||||
|
i.columns = append(i.columns, Column{name, ConvertValue(value)})
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *insertColumns) AddValues(values Values) *insertClause {
|
||||||
|
ic := &insertClause{builder: i.builder}
|
||||||
|
return ic.AddValues(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *insertClause) AddValues(values Values) *insertClause {
|
||||||
|
for name, value := range values {
|
||||||
|
i.columns = append(i.columns, Column{name, ConvertValue(value)})
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *insertClause) Build() string {
|
||||||
|
var columns, values string
|
||||||
|
for _, col := range i.columns {
|
||||||
|
columns += fmt.Sprintf("%s, ", col.Name)
|
||||||
|
values += fmt.Sprintf("%s, ", col.Type.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim off trailing delimiter
|
||||||
|
columns = strings.TrimRight(columns, ", ")
|
||||||
|
values = strings.TrimRight(values, ", ")
|
||||||
|
return fmt.Sprintf("%s(%s) VALUES(%s);", i.builder.stmt, columns, values)
|
||||||
|
}
|
||||||
61
pkg/artisan/select.go
Normal file
61
pkg/artisan/select.go
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NONE selectAttribute = iota
|
||||||
|
DISTINCT
|
||||||
|
ALL
|
||||||
|
)
|
||||||
|
|
||||||
|
type selectAttribute int
|
||||||
|
type selectArg string
|
||||||
|
type selectClause struct{ builder *Builder }
|
||||||
|
type selectOptional struct{ builder *Builder }
|
||||||
|
|
||||||
|
// Select() initiates a new SQL using a builder object. Calling this function
|
||||||
|
// will call the builders Reset() function and clear the current statement.
|
||||||
|
func (b *Builder) Select(what ...selectArg) *selectOptional {
|
||||||
|
b.Reset()
|
||||||
|
if len(what) == 0 {
|
||||||
|
b.stmt += "SELECT *"
|
||||||
|
} else {
|
||||||
|
var output string
|
||||||
|
for _, s := range what {
|
||||||
|
output += string(s) + ", "
|
||||||
|
}
|
||||||
|
output = strings.TrimRight(output, ", ")
|
||||||
|
b.stmt += fmt.Sprintf("SELECT %s", output)
|
||||||
|
}
|
||||||
|
return &selectOptional{builder: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selectOptional) WithAttribute(attribute selectAttribute) *selectClause {
|
||||||
|
switch attribute {
|
||||||
|
case NONE:
|
||||||
|
s.builder.stmt += ""
|
||||||
|
case DISTINCT:
|
||||||
|
s.builder.stmt += " DISTINCT"
|
||||||
|
case ALL:
|
||||||
|
s.builder.stmt += " ALL"
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return &selectClause{builder: s.builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selectOptional) From(table tablename) *fromClause {
|
||||||
|
sc := &selectClause{builder: s.builder}
|
||||||
|
return sc.From(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selectClause) From(table tablename) *fromClause {
|
||||||
|
s.builder.stmt += fmt.Sprintf(" FROM %s", table)
|
||||||
|
return &fromClause{builder: s.builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *fromClause) Build() string {
|
||||||
|
return s.builder.stmt + ";"
|
||||||
|
}
|
||||||
63
pkg/artisan/type.go
Normal file
63
pkg/artisan/type.go
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Column struct {
|
||||||
|
Name string
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
type Columns map[string]Type
|
||||||
|
type Values map[string]any
|
||||||
|
|
||||||
|
// define abstract interfaces
|
||||||
|
type Type interface {
|
||||||
|
Name() string
|
||||||
|
Value() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// define functions
|
||||||
|
func AllColumns() selectArg {
|
||||||
|
return "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
// define concrete SQLite types
|
||||||
|
type Base struct{ value string }
|
||||||
|
type Text struct{ Base }
|
||||||
|
type Integer struct{ Base }
|
||||||
|
type Real struct{ Base }
|
||||||
|
type Bool struct{ Base }
|
||||||
|
|
||||||
|
// define type name/value functions
|
||||||
|
func (b Base) Value() string { return b.value }
|
||||||
|
func (Base) Name() string { return "TEXT" }
|
||||||
|
func (Text) Name() string { return "TEXT" }
|
||||||
|
func (Integer) Name() string { return "INTEGER" }
|
||||||
|
func (Real) Name() string { return "REAL" }
|
||||||
|
func (Bool) Name() string { return "BOOLEAN" }
|
||||||
|
|
||||||
|
// define string interface functions for printing
|
||||||
|
func (t Text) String() string { return t.Value() }
|
||||||
|
func (i Integer) String() string { return i.Value() }
|
||||||
|
func (r Real) String() string { return r.Value() }
|
||||||
|
|
||||||
|
type IntegerType interface{ ~int | ~int32 | ~int64 }
|
||||||
|
|
||||||
|
func ConvertValue(value any) Type {
|
||||||
|
s := fmt.Sprint(value)
|
||||||
|
switch reflect.TypeOf(value).Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return Text{Base{fmt.Sprintf("\"%s\"", s)}}
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return Integer{Base{s}}
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return Integer{Base{s}}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return Real{Base{s}}
|
||||||
|
case reflect.Bool:
|
||||||
|
return Bool{Base{s}}
|
||||||
|
}
|
||||||
|
return Base{s}
|
||||||
|
}
|
||||||
43
pkg/artisan/update.go
Normal file
43
pkg/artisan/update.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type updateClause struct{ builder *Builder }
|
||||||
|
type setClause struct{ builder *Builder }
|
||||||
|
|
||||||
|
func (b *Builder) Update(table tablename) *updateClause {
|
||||||
|
b.stmt = fmt.Sprintf("UPDATE %s", table)
|
||||||
|
return &updateClause{builder: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *updateClause) Set(values Values) *setClause {
|
||||||
|
columns := ""
|
||||||
|
for name, value := range values {
|
||||||
|
columns += fmt.Sprintf("%s = %v, ", name, value)
|
||||||
|
}
|
||||||
|
s.builder.stmt += strings.TrimRight(columns, ", ")
|
||||||
|
return &setClause{builder: s.builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setClause) Where(condition conditional) *whereClause {
|
||||||
|
s.builder.stmt += fmt.Sprintf(" WHERE %s", condition)
|
||||||
|
return &whereClause{builder: s.builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *whereClause) OrderBy(column string) *whereClause {
|
||||||
|
s.builder.stmt += fmt.Sprintf(" ORDER BY %s", column)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *whereClause) Limit(rowcount int) *whereClause {
|
||||||
|
s.builder.stmt += fmt.Sprintf(" LIMIT %d", rowcount)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *whereClause) Offset(offset int) *whereClause {
|
||||||
|
s.builder.stmt += fmt.Sprintf(" OFFSET %d", offset)
|
||||||
|
return s
|
||||||
|
}
|
||||||
12
pkg/artisan/where.go
Normal file
12
pkg/artisan/where.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package artisan
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func (s *fromClause) Where(condition conditional) *whereClause {
|
||||||
|
s.builder.stmt += fmt.Sprintf(" WHERE %s", condition)
|
||||||
|
return &whereClause{builder: s.builder}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *whereClause) Build() string {
|
||||||
|
return s.builder.stmt + ";"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue