sqlite.*sqLiteStorage.BuildStructure   B
last analyzed

Complexity

Conditions 7

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nop 2
dl 0
loc 29
rs 8
c 0
b 0
f 0
1
package sqlite
2
3
import (
4
	"adrianolaselva.github.io/csvql/pkg/storage"
5
	"database/sql"
6
	"fmt"
7
	_ "github.com/mattn/go-sqlite3"
8
	"strings"
9
)
10
11
const (
12
	sqlCreateTableTemplate        = "CREATE TABLE IF NOT EXISTS %s (%s\n);"
13
	sqlInsertTemplate             = "INSERT INTO %s (%s) VALUES (%s);"
14
	sqlInsertDefaultTableTemplate = "INSERT INTO `schemas` (`id`, `name`, `columns`, `total_columns`) VALUES ((select count(1)+1 FROM `schemas`),?,?,?);"
15
	sqlShowTablesTemplate         = "select * from `schemas`;"
16
	sqlDefaultTableTemplate       = "CREATE TABLE IF NOT EXISTS `schemas` (`id` INTEGER, `name` text, `columns` text, `total_columns` INTEGER);"
17
	dataSourceNameDefault         = ":memory:"
18
)
19
20
type sqLiteStorage struct {
21
	db *sql.DB
22
}
23
24
func NewSqLiteStorage(datasource string) (storage.Storage, error) {
25
	if datasource == "" {
26
		datasource = dataSourceNameDefault
27
	}
28
29
	db, err := sql.Open("sqlite3", datasource)
30
	if err != nil {
31
		return nil, fmt.Errorf("failed to open connection with sqlite3: %w", err)
32
	}
33
34
	return &sqLiteStorage{db: db}, nil
35
}
36
37
// BuildStructure build table creation statement
38
func (s *sqLiteStorage) BuildStructure(tableName string, columns []string) error {
39
	var tableAttrsRaw strings.Builder
40
41
	for i, v := range columns {
42
		columns[i] = fmt.Sprintf("`%v`", v)
43
	}
44
45
	for i, v := range columns {
46
		tableAttrsRaw.WriteString(fmt.Sprintf("\n\t%s text", v))
47
		if len(columns)-1 > i {
48
			tableAttrsRaw.WriteString(",")
49
		}
50
	}
51
52
	query := fmt.Sprintf(sqlCreateTableTemplate, tableName, tableAttrsRaw.String())
53
	if _, err := s.db.Exec(query); err != nil {
54
		return fmt.Errorf("failed to create structure: %w (sql: %s)", err, query)
55
	}
56
57
	if _, err := s.db.Exec(sqlDefaultTableTemplate); err != nil {
58
		return fmt.Errorf("failed to create tables schemas structure: %w", err)
59
	}
60
61
	columnsRaw := fmt.Sprintf("[%v]", strings.Join(columns, ","))
62
	if _, err := s.db.Exec(sqlInsertDefaultTableTemplate, []any{tableName, columnsRaw, len(columns)}...); err != nil {
63
		return fmt.Errorf("failed to execute insert: %w", err)
64
	}
65
66
	return nil
67
}
68
69
// InsertRow build insert create statement
70
func (s *sqLiteStorage) InsertRow(tableName string, columns []string, values []any) error {
71
	columnsRaw := strings.Join(columns, ", ")
72
	paramsRaw := strings.Repeat("?, ", len(columns))
73
	query := fmt.Sprintf(sqlInsertTemplate, tableName, columnsRaw, paramsRaw[:len(paramsRaw)-2])
74
75
	if _, err := s.db.Exec(query, values...); err != nil {
76
		return fmt.Errorf("failed to execute insert: %w (sql: %s)", err, query)
77
	}
78
79
	return nil
80
}
81
82
// Query execute statements
83
func (s *sqLiteStorage) Query(cmd string) (*sql.Rows, error) {
84
	rows, err := s.db.Query(cmd)
85
	if err != nil {
86
		return nil, fmt.Errorf("failed to execute query: %w", err)
87
	}
88
89
	return rows, nil
90
}
91
92
func (s *sqLiteStorage) ShowTables() (*sql.Rows, error) {
93
	rows, err := s.db.Query(sqlShowTablesTemplate)
94
	if err != nil {
95
		return nil, fmt.Errorf("failed to execute query: %w", err)
96
	}
97
98
	return rows, nil
99
}
100
101
// Close execute in defer
102
func (s *sqLiteStorage) Close() error {
103
	err := s.db.Close()
104
	if err != nil {
105
		return fmt.Errorf("failed to close sqlite3 connection: %w", err)
106
	}
107
108
	return nil
109
}
110