@@ -3,6 +3,7 @@ package dbt
3
3
import (
4
4
"fmt"
5
5
"path/filepath"
6
+ "strconv"
6
7
"strings"
7
8
8
9
"github.com/pterm/pterm"
@@ -16,6 +17,7 @@ const (
16
17
timestampType = "timestamp"
17
18
doubleType = "double"
18
19
booleanType = "boolean"
20
+ postgresType = "postgres"
19
21
)
20
22
21
23
// Constants for SQL data types
@@ -73,10 +75,12 @@ func FromDbtProfiles(profiles *DbtProfiles) ([]DataSource, error) {
73
75
// convertConnectionToDataSource converts connection to corresponding DataSource based on connection type
74
76
func convertConnectionToDataSource (conn DbtConnection , dbtHomePath , profileName , outputName string ) (DataSource , error ) {
75
77
switch strings .ToLower (conn .Type ) {
76
- case "postgres" , "postgresql" :
78
+ case postgresType , "postgresql" :
77
79
return convertToPostgresDataSource (conn )
78
80
case "duckdb" :
79
81
return convertToLocalFileDataSource (conn , dbtHomePath )
82
+ case "mysql" :
83
+ return convertToMysqlDataSource (conn )
80
84
default :
81
85
// For unsupported database types, we can choose to ignore or return error
82
86
// Here we choose to return nil and log a warning
@@ -87,19 +91,26 @@ func convertConnectionToDataSource(conn DbtConnection, dbtHomePath, profileName,
87
91
88
92
// convertToPostgresDataSource converts to PostgreSQL data source
89
93
func convertToPostgresDataSource (conn DbtConnection ) (* WrenPostgresDataSource , error ) {
94
+ // For PostgreSQL, prefer dbname over database field
95
+ dbName := conn .DbName
96
+ if dbName == "" {
97
+ dbName = conn .Database
98
+ }
99
+
100
+ pterm .Info .Printf ("Converting Postgres data source: %s:%d/%s\n " , conn .Host , conn .Port , dbName )
101
+ port := strconv .Itoa (conn .Port )
102
+ if conn .Port == 0 {
103
+ port = "5432"
104
+ }
105
+
90
106
ds := & WrenPostgresDataSource {
91
107
Host : conn .Host ,
92
- Port : conn . Port ,
93
- Database : conn . Database ,
108
+ Port : port ,
109
+ Database : dbName ,
94
110
User : conn .User ,
95
111
Password : conn .Password ,
96
112
}
97
113
98
- // If no port is specified, use PostgreSQL default port
99
- if ds .Port == 0 {
100
- ds .Port = 5432
101
- }
102
-
103
114
return ds , nil
104
115
}
105
116
@@ -143,6 +154,30 @@ func convertToLocalFileDataSource(conn DbtConnection, dbtHome string) (*WrenLoca
143
154
}, nil
144
155
}
145
156
157
+ func convertToMysqlDataSource (conn DbtConnection ) (* WrenMysqlDataSource , error ) {
158
+ pterm .Info .Printf ("Converting MySQL data source: %s:%d/%s\n " , conn .Host , conn .Port , conn .Database )
159
+
160
+ sslMode := "ENABLED" // Default SSL mode
161
+ if conn .SslDisable {
162
+ sslMode = "DISABLED"
163
+ }
164
+ port := strconv .Itoa (conn .Port )
165
+ if conn .Port == 0 {
166
+ port = "3306"
167
+ }
168
+
169
+ ds := & WrenMysqlDataSource {
170
+ Host : conn .Host ,
171
+ Port : port ,
172
+ Database : conn .Database ,
173
+ User : conn .User ,
174
+ Password : conn .Password ,
175
+ SslMode : sslMode ,
176
+ }
177
+
178
+ return ds , nil
179
+ }
180
+
146
181
type WrenLocalFileDataSource struct {
147
182
Url string `json:"url"`
148
183
Format string `json:"format"`
@@ -189,15 +224,15 @@ func (ds *WrenLocalFileDataSource) MapType(sourceType string) string {
189
224
190
225
type WrenPostgresDataSource struct {
191
226
Host string `json:"host"`
192
- Port int `json:"port"`
227
+ Port string `json:"port"`
193
228
Database string `json:"database"`
194
229
User string `json:"user"`
195
230
Password string `json:"password"`
196
231
}
197
232
198
233
// GetType implements DataSource interface
199
234
func (ds * WrenPostgresDataSource ) GetType () string {
200
- return "postgres"
235
+ return postgresType
201
236
}
202
237
203
238
// Validate implements DataSource interface
@@ -211,7 +246,14 @@ func (ds *WrenPostgresDataSource) Validate() error {
211
246
if ds .User == "" {
212
247
return fmt .Errorf ("user cannot be empty" )
213
248
}
214
- if ds .Port <= 0 || ds .Port > 65535 {
249
+ if ds .Port == "" {
250
+ return fmt .Errorf ("port must be specified" )
251
+ }
252
+ port , err := strconv .Atoi (ds .Port )
253
+ if err != nil {
254
+ return fmt .Errorf ("port must be a valid number" )
255
+ }
256
+ if port <= 0 || port > 65535 {
215
257
return fmt .Errorf ("port must be between 1 and 65535" )
216
258
}
217
259
return nil
@@ -222,6 +264,83 @@ func (ds *WrenPostgresDataSource) MapType(sourceType string) string {
222
264
return sourceType
223
265
}
224
266
267
+ type WrenMysqlDataSource struct {
268
+ Database string `json:"database"`
269
+ Host string `json:"host"`
270
+ Password string `json:"password"`
271
+ Port string `json:"port"`
272
+ User string `json:"user"`
273
+ SslCA string `json:"ssl_ca,omitempty"` // Optional SSL CA file for MySQL
274
+ SslMode string `json:"ssl_mode,omitempty"` // Optional SSL mode for MySQL
275
+ }
276
+
277
+ // GetType implements DataSource interface
278
+ func (ds * WrenMysqlDataSource ) GetType () string {
279
+ return "mysql"
280
+ }
281
+
282
+ // Validate implements DataSource interface
283
+ func (ds * WrenMysqlDataSource ) Validate () error {
284
+ if ds .Host == "" {
285
+ return fmt .Errorf ("host cannot be empty" )
286
+ }
287
+ if ds .Database == "" {
288
+ return fmt .Errorf ("database cannot be empty" )
289
+ }
290
+ if ds .User == "" {
291
+ return fmt .Errorf ("user cannot be empty" )
292
+ }
293
+ if ds .Port == "" {
294
+ return fmt .Errorf ("port must be specified" )
295
+ }
296
+ port , err := strconv .Atoi (ds .Port )
297
+ if err != nil {
298
+ return fmt .Errorf ("port must be a valid number" )
299
+ }
300
+ if port <= 0 || port > 65535 {
301
+ return fmt .Errorf ("port must be between 1 and 65535" )
302
+ }
303
+ return nil
304
+ }
305
+
306
+ func (ds * WrenMysqlDataSource ) MapType (sourceType string ) string {
307
+ // This method is not used in WrenMysqlDataSource, but required by DataSource interface
308
+ sourceType = strings .ToUpper (sourceType )
309
+ switch sourceType {
310
+ case "CHAR" :
311
+ return "char"
312
+ case "VARCHAR" :
313
+ return varcharType
314
+ case "TEXT" , "TINYTEXT" , "MEDIUMTEXT" , "LONGTEXT" , "ENUM" , "SET" :
315
+ return "text"
316
+ case "BIT" , "TINYINT" :
317
+ return "TINYINT"
318
+ case "SMALLINT" :
319
+ return "SMALLINT"
320
+ case "MEDIUMINT" , "INT" , "INTEGER" :
321
+ return "INTEGER"
322
+ case "BIGINT" :
323
+ return "BIGINT"
324
+ case "FLOAT" , "DOUBLE" :
325
+ return "DOUBLE"
326
+ case "DECIMAL" , "NUMERIC" :
327
+ return "DECIMAL"
328
+ case "DATE" :
329
+ return "DATE"
330
+ case "DATETIME" :
331
+ return "DATETIME"
332
+ case "TIMESTAMP" :
333
+ return "TIMESTAMPTZ"
334
+ case "BOOLEAN" , "BOOL" :
335
+ return "BOOLEAN"
336
+ case "JSON" :
337
+ return "JSON"
338
+ default :
339
+ // Return the original type if no mapping is found
340
+ return strings .ToLower (sourceType )
341
+ }
342
+ }
343
+
225
344
// GetActiveDataSources gets active data sources based on specified profile and target
226
345
// If profileName is empty, it will use the first found profile
227
346
// If targetName is empty, it will use the profile's default target
@@ -326,7 +445,7 @@ func (d *DefaultDataSource) MapType(sourceType string) string {
326
445
case "integer" , "int" , "bigint" , "int64" :
327
446
return "integer"
328
447
case "varchar" , "text" , "string" , "char" :
329
- return "varchar"
448
+ return varcharType
330
449
case "timestamp" , "datetime" , "date" :
331
450
return "timestamp"
332
451
case "double" , "float" , "decimal" , "numeric" :
0 commit comments