Passed
Push — add-integration-tests ( dc0b51...907fca )
by Frank
21:07 queued 08:09
created

database.*Postgresql.GetIntegerDatatypes   A

Complexity

Conditions 1

Size

Total Lines 8
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 8
nop 0
dl 0
loc 8
ccs 0
cts 1
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
package database
2
3
import (
4
	"fmt"
5
	"strings"
6
7
	"github.com/fraenky8/tables-to-go/pkg/settings"
8
9
	// postgres database driver
10
	_ "github.com/lib/pq"
11
)
12
13
const (
14
	PostgresqlColumnTypePrimaryKey    = "PRIMARY KEY"
15
	PostgresqlColumnTypeAutoIncrement = "nextval"
16
	PostgresqlColumnTypeSerial        = "serial"
17
)
18
19
// Postgresql implements the Database interface with help of generalDatabase
20
type Postgresql struct {
21
	*GeneralDatabase
22
23
	defaultUserName string
24
25
	integerDataTypes map[string]struct{}
26
}
27
28
// NewPostgresql creates a new Postgresql database
29
func NewPostgresql(s *settings.Settings) *Postgresql {
30 1
	return &Postgresql{
31
		GeneralDatabase: &GeneralDatabase{
32
			Settings: s,
33
			driver:   dbTypeToDriverMap[s.DbType],
34
		},
35
		defaultUserName: "postgres",
36
37
		integerDataTypes: map[string]struct{}{
38
			"smallint":    {},
39
			"int2":        {},
40
			"integer":     {},
41
			"int4":        {},
42
			"bigint":      {},
43
			"int8":        {},
44
			"smallserial": {},
45
			"serial2":     {},
46
			"serial":      {},
47
			"serial4":     {},
48
			"bigserial":   {},
49
			"serial8":     {},
50
		},
51
	}
52
}
53
54
// Connect connects to the database by the given data source name (dsn) of the concrete database
55
func (pg *Postgresql) Connect() error {
56
	return pg.GeneralDatabase.Connect(pg.DSN())
57
}
58
59
// DSN creates the DSN String to connect to this database
60
func (pg *Postgresql) DSN() string {
61 1
	user := pg.defaultUserName
62 1
	if pg.Settings.User != "" {
63 1
		user = pg.Settings.User
64
	}
65 1
	return fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v sslmode=disable",
66
		pg.Settings.Host, pg.Settings.Port, user, pg.Settings.DbName, pg.Settings.Pswd)
67
}
68
69
// GetDriverImportLibrary returns the golang sql driver specific fot the Postgres database
70
func (pg *Postgresql) GetDriverImportLibrary() string {
71
	return "pg \"github.com/lib/pq\""
72
}
73
74
// GetTables gets all tables for a given schema by name
75
func (pg *Postgresql) GetTables() (tables []*Table, err error) {
76
77
	err = pg.Select(&tables, `
78
		SELECT table_name
79
		FROM information_schema.tables
80
		WHERE table_type = 'BASE TABLE'
81
		AND table_schema = $1
82
		ORDER BY table_name
83
	`, pg.Schema)
84
85
	if pg.Verbose {
86
		if err != nil {
87
			fmt.Println("> Error at GetTables()")
88
			fmt.Printf("> schema: %q\r\n", pg.Schema)
89
		}
90
	}
91
92
	return tables, err
93
}
94
95
// PrepareGetColumnsOfTableStmt prepares the statement for retrieving the columns of a specific table for a given database
96
func (pg *Postgresql) PrepareGetColumnsOfTableStmt() (err error) {
97
98
	pg.GetColumnsOfTableStmt, err = pg.Preparex(`
99
		SELECT
100
			ic.ordinal_position,
101
			ic.column_name,
102
			ic.data_type,
103
			ic.column_default,
104
			ic.is_nullable,
105
			ic.character_maximum_length,
106
			ic.numeric_precision,
107
			itc.constraint_name,
108
			itc.constraint_type
109
		FROM information_schema.columns AS ic
110
			LEFT JOIN information_schema.key_column_usage AS ikcu ON ic.table_name = ikcu.table_name
111
			AND ic.table_schema = ikcu.table_schema
112
			AND ic.column_name = ikcu.column_name
113
			LEFT JOIN information_schema.table_constraints AS itc ON ic.table_name = itc.table_name
114
			AND ic.table_schema = itc.table_schema
115
			AND ikcu.constraint_name = itc.constraint_name
116
		WHERE ic.table_name = $1
117
		AND ic.table_schema = $2
118
		ORDER BY ic.ordinal_position
119
	`)
120
121
	return err
122
}
123
124
// GetColumnsOfTable executes the statement for retrieving the columns of a specific table in a given schema
125
func (pg *Postgresql) GetColumnsOfTable(table *Table) (err error) {
126
127
	err = pg.GetColumnsOfTableStmt.Select(&table.Columns, table.Name, pg.Schema)
128
129
	if pg.Verbose {
130
		if err != nil {
131
			fmt.Printf("> Error at GetColumnsOfTable(%v)\r\n", table.Name)
132
			fmt.Printf("> schema: %q\r\n", pg.Schema)
133
		}
134
	}
135
136
	return err
137
}
138
139
// IsPrimaryKey checks if column belongs to primary key
140
func (pg *Postgresql) IsPrimaryKey(column Column) bool {
141
	return strings.Contains(column.ConstraintType.String, PostgresqlColumnTypePrimaryKey)
142
}
143
144
// IsAutoIncrement checks if column is a serial column
145
func (pg *Postgresql) IsAutoIncrement(column Column) bool {
146
	return strings.Contains(column.DefaultValue.String, PostgresqlColumnTypeAutoIncrement)
147
}
148
149
// GetStringDatatypes returns the string datatypes for the Postgres database
150
func (pg *Postgresql) GetStringDatatypes() []string {
151
	return []string{
152
		"character varying",
153
		"varchar",
154
		"character",
155
		"char",
156
	}
157
}
158
159
// IsString returns true if column is of type string for the Postgres database
160
func (pg *Postgresql) IsString(column Column) bool {
161
	return pg.IsStringInSlice(column.DataType, pg.GetStringDatatypes())
162
}
163
164
// GetTextDatatypes returns the text datatypes for the Postgres database
165
func (pg *Postgresql) GetTextDatatypes() []string {
166
	return []string{
167
		"text",
168
	}
169
}
170
171
// IsText returns true if column is of type text for the Postgres database
172
func (pg *Postgresql) IsText(column Column) bool {
173
	return pg.IsStringInSlice(column.DataType, pg.GetTextDatatypes())
174
}
175
176
// GetIntegerDatatypes returns the integer datatypes for the Postgres database
177
// TODO remove these methods
178
func (pg *Postgresql) GetIntegerDatatypes() []string {
179
	return []string{
180
		"smallint", "int2",
181
		"integer", "int4",
182
		"bigint", "int8",
183
		"smallserial", "serial2",
184
		"serial", "serial4",
185
		"bigserial", "serial8",
186
	}
187
}
188
189
// IsInteger returns true if column is of type integer for the Postgres database
190
func (pg *Postgresql) IsInteger(column Column) bool {
191
	_, ok := pg.integerDataTypes[column.DataType]
192
	return ok
193
}
194
195
// GetFloatDatatypes returns the float datatypes for the Postgres database
196
func (pg *Postgresql) GetFloatDatatypes() []string {
197
	return []string{
198
		"float",
199
		"float4",
200
		"float8",
201
		"numeric",
202
		"decimal",
203
		"real",
204
		"double precision",
205
	}
206
}
207
208
// IsFloat returns true if column is of type float for the Postgres database
209
func (pg *Postgresql) IsFloat(column Column) bool {
210
	return pg.IsStringInSlice(column.DataType, pg.GetFloatDatatypes())
211
}
212
213
// GetTemporalDatatypes returns the temporal datatypes for the Postgres database
214
func (pg *Postgresql) GetTemporalDatatypes() []string {
215
	return []string{
216
		"time",
217
		"timestamp",
218
		"time with time zone",
219
		"timestamp with time zone",
220
		"time without time zone",
221
		"timestamp without time zone",
222
		"date",
223
	}
224
}
225
226
// IsTemporal returns true if column is of type temporal for the Postgres database
227
func (pg *Postgresql) IsTemporal(column Column) bool {
228
	return pg.IsStringInSlice(column.DataType, pg.GetTemporalDatatypes())
229
}
230
231
// GetTemporalDriverDataType returns the time data type specific for the Postgres database
232
func (pg *Postgresql) GetTemporalDriverDataType() string {
233
	return "pg.NullTime"
234
}
235