1package norm
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7 "strings"
8)
9
10type insert struct {
11 into string
12 or InsertOr
13 values []struct {
14 col string
15 val any
16 }
17}
18
19type InsertOr int
20
21const (
22 None InsertOr = iota
23 Abort
24 Fail
25 Ignore
26 Replace
27 Rollback
28)
29
30func (i InsertOr) String() string {
31 switch i {
32 case Abort:
33 return "ABORT"
34 case Fail:
35 return "FAIL"
36 case Ignore:
37 return "IGNORE"
38 case Replace:
39 return "REPLACE"
40 case Rollback:
41 return "ROLLBACK"
42 default:
43 return ""
44 }
45}
46
47func Insert() insert {
48 return insert{}
49}
50
51type InsertOpt func(s *insert)
52
53func (s insert) Into(table string) insert {
54 s.into = table
55 return s
56}
57
58func (s insert) Or(option InsertOr) insert {
59 s.or = option
60 return s
61}
62
63func (s insert) Value(column string, arg any) insert {
64 s.values = append(s.values, struct {
65 col string
66 val any
67 }{
68 column, arg,
69 })
70 return s
71}
72
73func (s insert) Values(values map[string]any) insert {
74 for column, arg := range values {
75 s = s.Value(column, arg)
76 }
77 return s
78}
79
80func (s insert) Compile() (string, []any, error) {
81 var sql strings.Builder
82 var args []any
83
84 sql.WriteString("INSERT ")
85
86 orKw := s.or.String()
87 if orKw != "" {
88 sql.WriteString("OR ")
89 sql.WriteString(s.or.String())
90 sql.WriteString(" ")
91 }
92
93 if s.into == "" {
94 return "", nil, fmt.Errorf("INTO clause is required")
95 }
96 sql.WriteString("INTO ")
97 sql.WriteString(s.into)
98
99 if len(s.values) == 0 {
100 return "", nil, fmt.Errorf("no values supplied")
101 }
102
103 sql.WriteString(" (")
104
105 for i, v := range s.values {
106 if i != 0 {
107 sql.WriteString(", ")
108 }
109
110 sql.WriteString(v.col)
111 args = append(args, v.val)
112 }
113
114 sql.WriteString(") VALUES (")
115 sql.WriteString(strings.TrimSuffix(strings.Repeat("?, ", len(s.values)), ", "))
116 sql.WriteString(")")
117
118 return sql.String(), args, nil
119}
120
121func (s insert) MustCompile() (string, []any) {
122 sql, args, err := s.Compile()
123 if err != nil {
124 panic(err)
125 }
126
127 return sql, args
128}
129
130func (s insert) Build(p Database) (*sql.Stmt, []any, error) { return Build(s, p) }
131func (s insert) MustBuild(p Database) (*sql.Stmt, []any) { return MustBuild(s, p) }
132
133func (s insert) Exec(p Database) (sql.Result, error) { return Exec(s, p) }
134func (s insert) ExecContext(ctx context.Context, p Database) (sql.Result, error) {
135 return ExecContext(ctx, s, p)
136}
137func (s insert) MustExec(p Database) sql.Result { return MustExec(s, p) }
138func (s insert) MustExecContext(ctx context.Context, p Database) sql.Result {
139 return MustExecContext(ctx, s, p)
140}