Compare commits

...

9 Commits
v0.0.9 ... main

Author SHA1 Message Date
Timon Ringwald
31258a50a4 improved Delete func 2022-09-06 10:51:21 +02:00
Timon Ringwald
2ce3d755bd improved Delete 2022-09-06 10:49:22 +02:00
Timon Ringwald
f7bae81df7 added Delete 2022-09-06 10:42:09 +02:00
Timon Ringwald
3f8e334dbb panic when initializing already initialized database 2022-08-04 09:37:01 +02:00
Timon Ringwald
6d24df4153 moved to git.milar.in 2022-08-03 21:45:35 +02:00
Timon Ringwald
09c2d07e54 removed leaked password 2022-07-12 21:06:43 +02:00
Timon Ringwald
e39d4c3a13 show sql query on sql error 2022-07-12 21:05:45 +02:00
Timon Ringwald
96484eba5a removed SQL syntax error 2022-07-12 21:01:49 +02:00
Timon Ringwald
b2e2f96eb0 replaced Database constructors with init functions 2022-07-12 20:56:33 +02:00
10 changed files with 94 additions and 109 deletions

61
db.go
View File

@ -2,42 +2,71 @@ package advsql
import ( import (
"database/sql" "database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
) )
type Database struct { type Database struct {
db *sql.DB db *sql.DB
closefuncs []func() error stmts map[string]*sql.Stmt
} }
func NewDatabase(conn *sql.DB) *Database { func InitDatabase(database *Database, conn *sql.DB) {
return &Database{ panicOnNil(database)
db: conn,
closefuncs: make([]func() error, 0), if database.db != nil {
panic("database is initialized already")
} }
*database = Database{
db: conn,
stmts: map[string]*sql.Stmt{},
}
database.init()
} }
func NewMysqlDatabase(host string, port uint16, user, pass, db string) *Database { func InitMysqlDatabase(database *Database, host string, port uint16, user, pass, db string) {
panicOnNil(database)
conn, err := sql.Open("mysql", connString(host, port, user, pass, db)) conn, err := sql.Open("mysql", connString(host, port, user, pass, db))
if err != nil { if err != nil {
panic(err) panic(err)
} }
return NewDatabase(conn)
InitDatabase(database, conn)
} }
func (db *Database) prepare(query string) *sql.Stmt { func panicOnNil(database *Database) {
s, err := db.db.Prepare(query) if database == nil {
if err != nil { panic("database is nil. initialize database variable with new()")
panic(err)
} }
db.closefuncs = append(db.closefuncs, s.Close) }
return s
func (db *Database) init() {
for _, globalQuery := range globalStmts {
if db == globalQuery.db {
db.stmt(globalQuery.query)
}
}
}
func (db *Database) stmt(query string) *sql.Stmt {
if stmt, ok := db.stmts[query]; ok {
return stmt
}
stmt, err := db.db.Prepare(query)
if err != nil {
panic(fmt.Errorf("compilation failed for query '%s' reason: %w", query, err))
}
db.stmts[query] = stmt
return stmt
} }
func (db *Database) Close() error { func (db *Database) Close() error {
for _, close := range db.closefuncs { for _, stmt := range db.stmts {
close() stmt.Close()
} }
return db.db.Close() return db.db.Close()
} }

View File

@ -9,33 +9,31 @@ import (
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
) )
var TestDatabase = new(Database)
type User struct { type User struct {
Name string Name string
Hash []byte Hash []byte
Salt string Salt string
} }
func UserDecoder(u *User, decode ScanFunc) error { func ScanUserPkFirst(u *User, encode ScanFunc) error {
return decode(&u.Name, &u.Hash, &u.Salt) return encode(&u.Name, &u.Hash, &u.Salt)
} }
func InsertUserEncoder(u *User, encode ScanFunc) error { func ScanUserPkLast(u *User, encode ScanFunc) error {
return encode(u.Name, u.Hash, u.Salt) return encode(&u.Hash, &u.Salt, &u.Name)
} }
func UpdateUserByNameEncoder(u *User, encode ScanFunc) error { var (
return encode(u.Salt, u.Name) InsertUser = Insert(TestDatabase, "INSERT INTO users VALUES (?, ?, ?)", ScanUserPkFirst)
} UpdateUser = Update(TestDatabase, "UPDATE users SET hash = ?, salt = ? WHERE name = ?", ScanUserPkLast)
GetUserByName = QueryOne(TestDatabase, "SELECT * FROM users WHERE namea = ?", ScanUserPkFirst)
)
func TestDB(t *testing.T) { func TestDB(t *testing.T) {
db := NewMysqlDatabase("ip", 3306, "username", "password", "database") InitMysqlDatabase(TestDatabase, "ip", 3306, "username", "password", "database")
defer db.Close() defer TestDatabase.Close()
insertUser := Insert(db, "INSERT INTO users VALUES (?, ?, ?)", InsertUserEncoder)
updateUser := Update(db, "UPDATE users SET salt = ? WHERE name = ?", UpdateUserByNameEncoder)
getUsers := QueryMany(db, "SELECT * FROM users WHERE name = ?", UserDecoder)
pw := sha512.Sum512([]byte("weiter")) pw := sha512.Sum512([]byte("weiter"))
timon := &User{ timon := &User{
@ -43,13 +41,11 @@ func TestDB(t *testing.T) {
Hash: pw[:], Hash: pw[:],
Salt: "salt", Salt: "salt",
} }
fmt.Println("insert:", insertUser(timon)) fmt.Println("insert:", InsertUser(timon))
timon.Hash = []byte("asd") timon.Hash = []byte("asd")
fmt.Println("update:", updateUser(timon)) fmt.Println("update:", UpdateUser(timon))
for user := range getUsers("tordarus") {
fmt.Printf("name: \"%s\" | hash: \"%s\" | salt: \"%s\"\n", user.Name, hex.EncodeToString(user.Hash), user.Salt)
}
user := GetUserByName("tordarus")
fmt.Printf("name: \"%s\" | hash: \"%s\" | salt: \"%s\"\n", user.Name, hex.EncodeToString(user.Hash), user.Salt)
} }

11
delete.go Normal file
View File

@ -0,0 +1,11 @@
package advsql
func Delete(db *Database, query string) DeleteFunc {
prepareGlobal(db, query)
return func(args ...interface{}) error {
s := db.stmt(query)
_, err := s.Exec(args...)
return err
}
}

View File

@ -11,4 +11,6 @@ type QueryOneContextFunc[T any] func(ctx context.Context, args ...interface{}) *
type InsertFunc[T any] func(v *T) error type InsertFunc[T any] func(v *T) error
type UpdateFunc[T any] func(v *T) error type UpdateFunc[T any] func(v *T) error
type DeleteFunc func(args ...interface{}) error
type ScanFunc = func(args ...interface{}) error type ScanFunc = func(args ...interface{}) error

12
global_stmts.go Normal file
View File

@ -0,0 +1,12 @@
package advsql
type globalStmt struct {
db *Database
query string
}
var globalStmts = []*globalStmt{}
func prepareGlobal(db *Database, query string) {
globalStmts = append(globalStmts, &globalStmt{db, query})
}

7
go.mod
View File

@ -1,8 +1,5 @@
module git.tordarus.net/Tordarus/advsql module git.milar.in/milarin/advsql
go 1.18 go 1.18
require ( require github.com/go-sql-driver/mysql v1.6.0
git.tordarus.net/Tordarus/adverr v0.2.0
github.com/go-sql-driver/mysql v1.6.0
)

2
go.sum
View File

@ -1,4 +1,2 @@
git.tordarus.net/Tordarus/adverr v0.2.0 h1:kLYjR2/Vb2GHiSAMvAv+WPNaHR9BRphKanf8H/pCZdA=
git.tordarus.net/Tordarus/adverr v0.2.0/go.mod h1:XRf0+7nhOkIEr0gi9DUG4RvV2KaOFB0fYPDaR1KLenw=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=

View File

@ -1,9 +1,10 @@
package advsql package advsql
func Insert[T any](db *Database, query string, encoder func(v *T, encode ScanFunc) error) InsertFunc[T] { func Insert[T any](db *Database, query string, encoder func(v *T, encode ScanFunc) error) InsertFunc[T] {
s := db.prepare(query) prepareGlobal(db, query)
return func(value *T) error { return func(value *T) error {
s := db.stmt(query)
return encoder(value, func(args ...interface{}) error { return encoder(value, func(args ...interface{}) error {
_, err := s.Exec(args...) _, err := s.Exec(args...)
return err return err

View File

@ -10,13 +10,11 @@ func QueryMany[T any](db *Database, query string, decoder func(v *T, decode Scan
} }
func QueryManyContext[T any](db *Database, query string, decoder func(v *T, decode ScanFunc) error) QueryManyContextFunc[T] { func QueryManyContext[T any](db *Database, query string, decoder func(v *T, decode ScanFunc) error) QueryManyContextFunc[T] {
s, err := db.db.Prepare(query) prepareGlobal(db, query)
if err != nil {
return nil
}
db.closefuncs = append(db.closefuncs, s.Close)
return func(ctx context.Context, args ...interface{}) <-chan *T { return func(ctx context.Context, args ...interface{}) <-chan *T {
s := db.stmt(query)
out := make(chan *T, 10) out := make(chan *T, 10)
rows, err := s.QueryContext(ctx, args...) rows, err := s.QueryContext(ctx, args...)

59
stmt.go
View File

@ -1,59 +0,0 @@
package advsql
// import (
// "database/sql"
// )
// type Stmt[M any] struct {
// stmt *sql.Stmt
// scan func(Scanner) (*M, error)
// }
// func NewStmt[M any](db *Database, query string, scan func(s Scanner) (*M, error)) (*Stmt[M], error) {
// s, err := db.db.Prepare(query)
// if err != nil {
// return nil, err
// }
// stmt := Stmt[M]{
// stmt: s,
// scan: scan,
// }
// db.closefuncs = append(db.closefuncs, stmt.Close)
// return &stmt, err
// }
// func (stmt *Stmt[M]) Close() error {
// return stmt.stmt.Close()
// }
// func (stmt *Stmt[M]) Many(args ...interface{}) (<-chan *M, error) {
// rows, err := stmt.stmt.Query(args...)
// if err != nil {
// return nil, err
// }
// out := make(chan *M, 10)
// go func() {
// defer rows.Close()
// defer close(out)
// for rows.Next() {
// if v, err := stmt.scan(rows); err == nil {
// out <- v
// }
// }
// }()
// return out, nil
// }
// func (stmt *Stmt[M]) Single(args ...interface{}) (*M, error) {
// rows, err := stmt.stmt.Query(args...)
// if err != nil {
// return nil, err
// }
// defer rows.Close()
// return stmt.scan(rows)
// }