1 package sqlgen_test
2
3 import (
4 "testing"
5
6 "github.com/doug-martin/goqu/v9/exp"
7 "github.com/doug-martin/goqu/v9/internal/errors"
8 "github.com/doug-martin/goqu/v9/internal/sb"
9 "github.com/doug-martin/goqu/v9/sqlgen"
10 "github.com/stretchr/testify/suite"
11 )
12
13 type (
14 deleteTestCase struct {
15 clause exp.DeleteClauses
16 sql string
17 isPrepared bool
18 args []interface{}
19 err string
20 }
21 deleteSQLGeneratorSuite struct {
22 baseSQLGeneratorSuite
23 }
24 )
25
26 func (dsgs *deleteSQLGeneratorSuite) assertCases(dsg sqlgen.DeleteSQLGenerator, testCases ...deleteTestCase) {
27 for _, tc := range testCases {
28 b := sb.NewSQLBuilder(tc.isPrepared)
29 dsg.Generate(b, tc.clause)
30 switch {
31 case len(tc.err) > 0:
32 dsgs.assertErrorSQL(b, tc.err)
33 case tc.isPrepared:
34 dsgs.assertPreparedSQL(b, tc.sql, tc.args)
35 default:
36 dsgs.assertNotPreparedSQL(b, tc.sql)
37 }
38 }
39 }
40
41 func (dsgs *deleteSQLGeneratorSuite) TestDialect() {
42 opts := sqlgen.DefaultDialectOptions()
43 d := sqlgen.NewDeleteSQLGenerator("test", opts)
44 dsgs.Equal("test", d.Dialect())
45
46 opts2 := sqlgen.DefaultDialectOptions()
47 d2 := sqlgen.NewDeleteSQLGenerator("test2", opts2)
48 dsgs.Equal("test2", d2.Dialect())
49 }
50
51 func (dsgs *deleteSQLGeneratorSuite) TestGenerate() {
52 dc := exp.NewDeleteClauses().
53 SetFrom(exp.NewIdentifierExpression("", "test", ""))
54
55 dsgs.assertCases(
56 sqlgen.NewDeleteSQLGenerator("test", sqlgen.DefaultDialectOptions()),
57 deleteTestCase{clause: dc, sql: `DELETE FROM "test"`},
58 deleteTestCase{clause: dc, sql: `DELETE FROM "test"`, isPrepared: true},
59 )
60
61 opts2 := sqlgen.DefaultDialectOptions()
62 opts2.DeleteClause = []byte("delete")
63
64 dsgs.assertCases(
65 sqlgen.NewDeleteSQLGenerator("test", opts2),
66 deleteTestCase{clause: dc, sql: `delete FROM "test"`},
67 deleteTestCase{clause: dc, sql: `delete FROM "test"`, isPrepared: true},
68 )
69 }
70
71 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_withUnsupportedFragment() {
72 opts := sqlgen.DefaultDialectOptions()
73 opts.DeleteSQLOrder = []sqlgen.SQLFragmentType{sqlgen.InsertBeingSQLFragment}
74 dc := exp.NewDeleteClauses().
75 SetFrom(exp.NewIdentifierExpression("", "test", ""))
76
77 dsgs.assertCases(
78 sqlgen.NewDeleteSQLGenerator("test", opts),
79 deleteTestCase{clause: dc, err: `goqu: unsupported DELETE SQL fragment InsertBeingSQLFragment`},
80 deleteTestCase{clause: dc, err: `goqu: unsupported DELETE SQL fragment InsertBeingSQLFragment`, isPrepared: true},
81 )
82 }
83
84 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_noFrom() {
85 dc := exp.NewDeleteClauses()
86 dsgs.assertCases(
87 sqlgen.NewDeleteSQLGenerator("test", sqlgen.DefaultDialectOptions()),
88 deleteTestCase{clause: dc, err: sqlgen.ErrNoSourceForDelete.Error()},
89 deleteTestCase{clause: dc, err: sqlgen.ErrNoSourceForDelete.Error(), isPrepared: true},
90 )
91 }
92
93 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_withErroredBuilder() {
94 opts := sqlgen.DefaultDialectOptions()
95 d := sqlgen.NewDeleteSQLGenerator("test", opts)
96
97 dc := exp.NewDeleteClauses().SetFrom(exp.NewIdentifierExpression("", "test", ""))
98 b := sb.NewSQLBuilder(false).SetError(errors.New("expected error"))
99 d.Generate(b, dc)
100 dsgs.assertErrorSQL(b, "goqu: expected error")
101
102 b = sb.NewSQLBuilder(true).SetError(errors.New("expected error"))
103 d.Generate(b, dc)
104 dsgs.assertErrorSQL(b, "goqu: expected error")
105 }
106
107 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_withCommonTables() {
108 opts := sqlgen.DefaultDialectOptions()
109 opts.WithFragment = []byte("with ")
110 opts.RecursiveFragment = []byte("recursive ")
111
112 tse := newTestAppendableExpression("select * from foo", emptyArgs, nil, nil)
113
114 dc := exp.NewDeleteClauses().SetFrom(exp.NewIdentifierExpression("", "test_cte", ""))
115 dcCte1 := dc.CommonTablesAppend(exp.NewCommonTableExpression(false, "test_cte", tse))
116 dcCte2 := dc.CommonTablesAppend(exp.NewCommonTableExpression(true, "test_cte", tse))
117
118 dsgs.assertCases(
119 sqlgen.NewDeleteSQLGenerator("test", opts),
120 deleteTestCase{clause: dcCte1, sql: `with test_cte AS (select * from foo) DELETE FROM "test_cte"`},
121 deleteTestCase{clause: dcCte1, sql: `with test_cte AS (select * from foo) DELETE FROM "test_cte"`, isPrepared: true},
122
123 deleteTestCase{clause: dcCte2, sql: `with recursive test_cte AS (select * from foo) DELETE FROM "test_cte"`},
124 deleteTestCase{clause: dcCte2, sql: `with recursive test_cte AS (select * from foo) DELETE FROM "test_cte"`, isPrepared: true},
125 )
126
127 opts.SupportsWithCTE = false
128 expectedErr := sqlgen.ErrCTENotSupported("test")
129 dsgs.assertCases(
130 sqlgen.NewDeleteSQLGenerator("test", opts),
131 deleteTestCase{clause: dcCte1, err: expectedErr.Error()},
132 deleteTestCase{clause: dcCte1, err: expectedErr.Error(), isPrepared: true},
133
134 deleteTestCase{clause: dcCte2, err: expectedErr.Error()},
135 deleteTestCase{clause: dcCte2, err: expectedErr.Error(), isPrepared: true},
136 )
137
138 opts.SupportsWithCTE = true
139 opts.SupportsWithCTERecursive = false
140 expectedErr = sqlgen.ErrRecursiveCTENotSupported("test")
141 dsgs.assertCases(
142 sqlgen.NewDeleteSQLGenerator("test", opts),
143 deleteTestCase{clause: dcCte1, sql: `with test_cte AS (select * from foo) DELETE FROM "test_cte"`},
144 deleteTestCase{clause: dcCte1, sql: `with test_cte AS (select * from foo) DELETE FROM "test_cte"`, isPrepared: true},
145
146 deleteTestCase{clause: dcCte2, err: expectedErr.Error()},
147 deleteTestCase{clause: dcCte2, err: expectedErr.Error(), isPrepared: true},
148 )
149 }
150
151 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_withWhere() {
152 dc := exp.NewDeleteClauses().
153 SetFrom(exp.NewIdentifierExpression("", "test", "")).
154 WhereAppend(exp.NewLiteralExpression(`"a"=?`, 1))
155 dsgs.assertCases(
156 sqlgen.NewDeleteSQLGenerator("test", sqlgen.DefaultDialectOptions()),
157 deleteTestCase{clause: dc, sql: `DELETE FROM "test" WHERE "a"=1`},
158 deleteTestCase{clause: dc, sql: `DELETE FROM "test" WHERE "a"=?`, isPrepared: true, args: []interface{}{
159 int64(1),
160 }},
161 )
162 }
163
164 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_withOrder() {
165 opts := sqlgen.DefaultDialectOptions()
166 opts.SupportsOrderByOnDelete = true
167
168 dc := exp.NewDeleteClauses().
169 SetFrom(exp.NewIdentifierExpression("", "test", "")).
170 SetOrder(exp.NewIdentifierExpression("", "", "c").Desc())
171
172 dsgs.assertCases(
173 sqlgen.NewDeleteSQLGenerator("test", opts),
174 deleteTestCase{clause: dc, sql: `DELETE FROM "test" ORDER BY "c" DESC`},
175 deleteTestCase{clause: dc, sql: `DELETE FROM "test" ORDER BY "c" DESC`, isPrepared: true},
176 )
177
178 opts.SupportsOrderByOnDelete = false
179 dsgs.assertCases(
180 sqlgen.NewDeleteSQLGenerator("test", opts),
181 deleteTestCase{clause: dc, sql: `DELETE FROM "test"`},
182 deleteTestCase{clause: dc, sql: `DELETE FROM "test"`, isPrepared: true},
183 )
184 }
185
186 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_withLimit() {
187 opts := sqlgen.DefaultDialectOptions()
188 opts.SupportsLimitOnDelete = true
189
190 dc := exp.NewDeleteClauses().
191 SetFrom(exp.NewIdentifierExpression("", "test", "")).
192 SetLimit(1)
193
194 dsgs.assertCases(
195 sqlgen.NewDeleteSQLGenerator("test", opts),
196 deleteTestCase{clause: dc, sql: `DELETE FROM "test" LIMIT 1`},
197 deleteTestCase{clause: dc, sql: `DELETE FROM "test" LIMIT ?`, isPrepared: true, args: []interface{}{int64(1)}},
198 )
199
200 opts.SupportsLimitOnDelete = false
201 dsgs.assertCases(
202 sqlgen.NewDeleteSQLGenerator("test", opts),
203 deleteTestCase{clause: dc, sql: `DELETE FROM "test"`},
204 deleteTestCase{clause: dc, sql: `DELETE FROM "test"`, isPrepared: true},
205 )
206 }
207
208 func (dsgs *deleteSQLGeneratorSuite) TestGenerate_withReturning() {
209 opts := sqlgen.DefaultDialectOptions()
210 opts.SupportsReturn = true
211
212 dc := exp.NewDeleteClauses().
213 SetFrom(exp.NewIdentifierExpression("", "test", "")).
214 SetReturning(exp.NewColumnListExpression("a", "b"))
215
216 dsgs.assertCases(
217 sqlgen.NewDeleteSQLGenerator("test", opts),
218 deleteTestCase{clause: dc, sql: `DELETE FROM "test" RETURNING "a", "b"`},
219 deleteTestCase{clause: dc, sql: `DELETE FROM "test" RETURNING "a", "b"`, isPrepared: true},
220 )
221
222 opts.SupportsReturn = false
223 expectedErr := `goqu: dialect does not support RETURNING clause [dialect=test]`
224 dsgs.assertCases(
225 sqlgen.NewDeleteSQLGenerator("test", opts),
226 deleteTestCase{clause: dc, err: expectedErr},
227 deleteTestCase{clause: dc, err: expectedErr, isPrepared: true},
228 )
229 }
230
231 func TestDeleteSQLGenerator(t *testing.T) {
232 suite.Run(t, new(deleteSQLGeneratorSuite))
233 }
234
View as plain text