adding mysql support, table creation tested, TODO schema

This commit is contained in:
ycc 2023-06-27 23:19:50 +02:00
parent cf652439b4
commit 974fab1d64
8 changed files with 368 additions and 19 deletions

View File

@ -3,6 +3,7 @@ package sqldb
import ( import (
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"html/template" "html/template"
"io/ioutil" "io/ioutil"
@ -11,6 +12,7 @@ import (
"strconv" "strconv"
"strings" "strings"
_ "github.com/go-sql-driver/mysql"
"github.com/lib/pq" "github.com/lib/pq"
) )
@ -63,12 +65,12 @@ func (db *Db) Table(name string) *TableInfo {
return &ti return &ti
} }
// GetAssociativeArray : Provide results as an associative array // GetAssociativeArray : Provide table data as an associative array
func (t *TableInfo) GetAssociativeArray(columns []string, restriction string, sortkeys []string, dir string) ([]AssRow, error) { func (t *TableInfo) GetAssociativeArray(columns []string, restriction string, sortkeys []string, dir string) ([]AssRow, error) {
return t.db.QueryAssociativeArray(t.buildSelect("", columns, restriction, sortkeys, dir)) return t.db.QueryAssociativeArray(t.buildSelect("", columns, restriction, sortkeys, dir))
} }
// QueryAssociativeArray : Provide results as an associative array // QueryAssociativeArray : Provide query result as an associative array
func (db *Db) QueryAssociativeArray(query string) (Rows, error) { func (db *Db) QueryAssociativeArray(query string) (Rows, error) {
rows, err := db.conn.Query(query) rows, err := db.conn.Query(query)
if err != nil { if err != nil {
@ -112,12 +114,21 @@ func (db *Db) QueryAssociativeArray(query string) (Rows, error) {
return results, nil return results, nil
} }
// GetSchema : Provide results as an associative array // GetSchema : Provide table schema as an associative array
func (t *TableInfo) GetSchema() (*TableInfo, error) { func (t *TableInfo) GetSchema() (*TableInfo, error) {
pgSchema := "SELECT column_name :: varchar as name, REPLACE(REPLACE(data_type,'character varying','varchar'),'character','char') || COALESCE('(' || character_maximum_length || ')', '') as type, col_description('public." + t.Name + "'::regclass, ordinal_position) as comment from INFORMATION_SCHEMA.COLUMNS where table_name ='" + t.Name + "';"
mySchema := "SELECT COLUMN_NAME as name, DATA_TYPE || CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + t.Name + "';"
var schemaQuery string
var ti TableInfo var ti TableInfo
ti.Name = t.Name ti.Name = t.Name
ti.db = t.db ti.db = t.db
cols, err := t.db.QueryAssociativeArray("SELECT column_name :: varchar as name, REPLACE(REPLACE(data_type,'character varying','varchar'),'character','char') || COALESCE('(' || character_maximum_length || ')', '') as type, col_description('public." + t.Name + "'::regclass, ordinal_position) as comment from INFORMATION_SCHEMA.COLUMNS where table_name ='" + t.Name + "';") if t.db.Driver == "postgres" {
schemaQuery = pgSchema
}
if t.db.Driver == "mysql" {
schemaQuery = mySchema
}
cols, err := t.db.QueryAssociativeArray(schemaQuery)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return nil, err return nil, err
@ -144,6 +155,7 @@ func (t *TableInfo) GetSchema() (*TableInfo, error) {
return &ti, nil return &ti, nil
} }
// GetSchema : Provide full database schema as an associative array
func (db *Db) GetSchema() ([]TableInfo, error) { func (db *Db) GetSchema() ([]TableInfo, error) {
var res []TableInfo var res []TableInfo
tables, err := db.ListTables() tables, err := db.ListTables()
@ -168,10 +180,25 @@ func (db *Db) GetSchema() ([]TableInfo, error) {
return res, nil return res, nil
} }
// GetSchema : Provide database tables list
func (db *Db) ListTables() (Rows, error) { func (db *Db) ListTables() (Rows, error) {
if db.Driver == "postgres" {
return db.pgListTables()
}
if db.Driver == "mysql" {
return db.myListTables()
}
return nil, errors.New("no driver")
}
func (db *Db) pgListTables() (Rows, error) {
return db.QueryAssociativeArray("SELECT table_name :: varchar as name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name;") return db.QueryAssociativeArray("SELECT table_name :: varchar as name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name;")
} }
func (db *Db) myListTables() (Rows, error) {
return db.QueryAssociativeArray("SELECT TABLE_NAME as name FROM information_schema.TABLES WHERE TABLE_TYPE LIKE 'BASE_TABLE';")
}
func (db *Db) CreateTable(t TableInfo) error { func (db *Db) CreateTable(t TableInfo) error {
t.db = db t.db = db
query := "create table " + t.Name + " ( " query := "create table " + t.Name + " ( "

29
docker-compose.yml Normal file
View File

@ -0,0 +1,29 @@
version: '3.1'
services:
pg:
image: postgres:alpine
restart: always
environment:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- 5432:5432
my:
image: mariadb:latest
restart: always
environment:
MYSQL_DATABASE: test
MYSQL_USER: test
MYSQL_PASSWORD: test
MARIADB_ROOT_PASSWORD: root
ports:
- 3306:3306
adminer:
image: adminer
restart: always
ports:
- 8080:8080

5
go.mod
View File

@ -2,4 +2,7 @@ module forge.redroom.link/yves/sqldb
go 1.17 go 1.17
require github.com/lib/pq v1.10.4 require (
github.com/go-sql-driver/mysql v1.7.1
github.com/lib/pq v1.10.4
)

2
go.sum
View File

@ -1,2 +1,4 @@
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=

230
my_test.go Executable file
View File

@ -0,0 +1,230 @@
package sqldb
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"testing"
)
func TestMyCreateTable(t *testing.T) {
db := Open("mysql", "test:test@tcp(127.0.0.1:3306)/test")
defer db.Close()
jsonFile, err := os.Open("test_table.json")
if err != nil {
fmt.Println(err)
}
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
var jsonSource TableInfo
json.Unmarshal([]byte(byteValue), &jsonSource)
err = db.CreateTable(jsonSource)
if err != nil {
fmt.Println(err.Error())
}
sch, err := db.Table("test").GetSchema()
if err != nil {
fmt.Println(err.Error())
}
if len(sch.Columns) == 0 {
t.Errorf("Create table failed")
}
}
func TestMyAddColumn(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
old, err := db.Table("test").GetSchema()
if err != nil {
fmt.Println(err.Error())
}
db.Table("test").AddColumn("addcolumn", "integer", "comment")
new, err := db.Table("test").GetSchema()
if err != nil {
fmt.Println(err.Error())
}
if len(old.Columns) == len(new.Columns) {
t.Errorf("Column already exist")
}
}
func TestMyInsert(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
vl := make(AssRow)
vl["name"] = "toto"
vl["description"] = "tata"
old, err := db.Table("test").GetAssociativeArray([]string{"*"}, "", []string{}, "")
if err != nil {
fmt.Println(err.Error())
}
jsonStringOld, _ := json.Marshal(old)
fmt.Println(string(jsonStringOld))
db.Table("test").UpdateOrInsert(vl)
new, err := db.Table("test").GetAssociativeArray([]string{"*"}, "", []string{}, "")
if err != nil {
fmt.Println(err.Error())
}
jsonStringNew, _ := json.Marshal(new)
fmt.Println(string(jsonStringNew))
if len(jsonStringOld) == len(jsonStringNew) {
t.Errorf("Error row not created")
}
jsonFile, err := os.Open("insert.json")
defer jsonFile.Close()
var result map[string]interface{}
byteValue, _ := ioutil.ReadAll(jsonFile)
json.Unmarshal(byteValue, &result)
}
func TestMyUpdate(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
vl := make(AssRow)
vl["id"] = 1
vl["name"] = "titi"
vl["description"] = "toto"
old, err := db.Table("test").GetAssociativeArray([]string{"*"}, "", []string{}, "")
if err != nil {
fmt.Println(err.Error())
}
jsonStringOld, _ := json.Marshal(old)
fmt.Println(string(jsonStringOld))
db.Table("test").UpdateOrInsert(vl)
new, err := db.Table("test").GetAssociativeArray([]string{"*"}, "", []string{}, "")
if err != nil {
fmt.Println(err.Error())
}
jsonStringNew, _ := json.Marshal(new)
fmt.Println(string(jsonStringNew))
if string(jsonStringOld) == string(jsonStringNew) {
t.Errorf("Error row not updated")
}
}
func TestMyDelete(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
vl := make(AssRow)
vl["id"] = 1
old, err := db.Table("test").GetAssociativeArray([]string{"*"}, "", []string{}, "")
if err != nil {
fmt.Println(err.Error())
}
jsonStringOld, _ := json.Marshal(old)
fmt.Println(string(jsonStringOld))
db.Table("test").Delete(vl)
new, err := db.Table("test").GetAssociativeArray([]string{"*"}, "", []string{}, "")
if err != nil {
fmt.Println(err.Error())
}
jsonStringNew, _ := json.Marshal(new)
fmt.Println(string(jsonStringNew))
if len(jsonStringOld) == len(jsonStringNew) {
t.Errorf("Error row not deleted")
}
}
func TestMyDeleteColumn(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
old, err := db.Table("test").GetSchema()
if err != nil {
fmt.Println(err.Error())
}
db.Table("test").DeleteColumn("addcolumn")
new, err := db.Table("test").GetSchema()
if err != nil {
fmt.Println(err.Error())
}
if len(old.Columns) == len(new.Columns) {
t.Errorf("Error column not deleted")
}
}
func TestMyDeleteTable(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
db.Table("test").DeleteTable()
}
func TestMyImportSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
db.ImportSchema("pfn.json")
}
func TestMyClearImportSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
db.ClearImportSchema("pfn.json")
}
func TestMyGetSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
data, err := db.GetSchema()
if err != nil {
fmt.Println(err.Error())
}
val, _ := json.Marshal(data)
fmt.Println(string(val))
}
func TestMySaveSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
err := db.SaveSchema("schema.json")
if err != nil {
fmt.Println(err.Error())
}
}
func TestMyGenerateTemplate(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
err := db.GenerateTemplate("plantuml.tmpl", "schema.puml")
if err != nil {
fmt.Println(err.Error())
}
}
func TestMyGenerateTableTemplate(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close()
err := db.GenerateTableTemplates("table.tmpl", "gen", "html")
if err != nil {
fmt.Println(err.Error())
}
}

View File

@ -8,7 +8,7 @@ import (
"testing" "testing"
) )
func TestCreateTable(t *testing.T) { func TestPgCreateTable(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
@ -37,7 +37,7 @@ func TestCreateTable(t *testing.T) {
} }
} }
func TestAddColumn(t *testing.T) { func TestPgAddColumn(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
@ -57,7 +57,7 @@ func TestAddColumn(t *testing.T) {
} }
} }
func TestInsert(t *testing.T) { func TestPgInsert(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
@ -92,7 +92,7 @@ func TestInsert(t *testing.T) {
json.Unmarshal(byteValue, &result) json.Unmarshal(byteValue, &result)
} }
func TestUpdate(t *testing.T) { func TestPgUpdate(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
@ -124,7 +124,7 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestPgDelete(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
@ -153,7 +153,7 @@ func TestDelete(t *testing.T) {
} }
} }
func TestDeleteColumn(t *testing.T) { func TestPgDeleteColumn(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
@ -173,26 +173,26 @@ func TestDeleteColumn(t *testing.T) {
} }
} }
func TestDeleteTable(t *testing.T) { func TestPgDeleteTable(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
db.Table("test").DeleteTable() db.Table("test").DeleteTable()
} }
func TestImportSchema(t *testing.T) { func TestPgImportSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
db.ImportSchema("pfn.json") db.ImportSchema("pfn.json")
} }
func TestClearImportSchema(t *testing.T) { func TestPgClearImportSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
db.ClearImportSchema("pfn.json") db.ClearImportSchema("pfn.json")
} }
func TestGetSchema(t *testing.T) { func TestPgGetSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
data, err := db.GetSchema() data, err := db.GetSchema()
@ -203,7 +203,7 @@ func TestGetSchema(t *testing.T) {
fmt.Println(string(val)) fmt.Println(string(val))
} }
func TestSaveSchema(t *testing.T) { func TestPgSaveSchema(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
err := db.SaveSchema("schema.json") err := db.SaveSchema("schema.json")
@ -211,7 +211,7 @@ func TestSaveSchema(t *testing.T) {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
} }
func TestGenerateTemplate(t *testing.T) { func TestPgGenerateTemplate(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
err := db.GenerateTemplate("plantuml.tmpl", "schema.puml") err := db.GenerateTemplate("plantuml.tmpl", "schema.puml")
@ -220,7 +220,7 @@ func TestGenerateTemplate(t *testing.T) {
} }
} }
func TestGenerateTableTemplate(t *testing.T) { func TestPgGenerateTableTemplate(t *testing.T) {
db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable") db := Open("postgres", "host=127.0.0.1 port=5432 user=test password=test dbname=test sslmode=disable")
defer db.Close() defer db.Close()
err := db.GenerateTableTemplates("table.tmpl", "gen", "html") err := db.GenerateTableTemplates("table.tmpl", "gen", "html")

58
survey.json Normal file
View File

@ -0,0 +1,58 @@
[
{
"name": "survey",
"columns": {
"id": "integer",
"name": "varchar(255)",
"description": "varchar(1000)",
"start":"timestmp",
"stop":"timestmpestamp",
"published":"bool"
}
},
{
"name": "surveyquestion",
"columns": {
"id": "integer",
"survey_id": "integer",
"question_id": "integer"
}
},
{
"name": "chapter",
"columns": {
"id": "integer",
"name": "varchar(255)",
"order": "integer"
}
},
{
"name": "question",
"columns": {
"name": "varchar(255)",
"text": "varchar(1000)",
"type": "varchar(255)",
"options": "varchar(1000)",
"id": "integer",
"order": "integer",
"chapter_id": "integer"
}
},
{
"name": "authuser",
"columns": {
"survey_id": "integer",
"code": "varchar(1000)",
"id": "integer"
}
},
{
"name": "answer",
"columns": {
"question_id": "integer",
"code_id": "integer",
"value":"integer",
"text": "varchar(2000)"
}
}
]

View File

@ -11,7 +11,7 @@
"longitude":"float|map", "longitude":"float|map",
"intvalue":"integer", "intvalue":"integer",
"floatvalue":"float", "floatvalue":"float",
"price":"money", "price":"float",
"testtype_id":"integer" "testtype_id":"integer"
} }
} }