Compare commits
No commits in common. "main" and "v0.0.9" have entirely different histories.
55
db.go
55
db.go
@ -2,71 +2,42 @@ 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
|
||||||
stmts map[string]*sql.Stmt
|
closefuncs []func() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitDatabase(database *Database, conn *sql.DB) {
|
func NewDatabase(conn *sql.DB) *Database {
|
||||||
panicOnNil(database)
|
return &Database{
|
||||||
|
|
||||||
if database.db != nil {
|
|
||||||
panic("database is initialized already")
|
|
||||||
}
|
|
||||||
|
|
||||||
*database = Database{
|
|
||||||
db: conn,
|
db: conn,
|
||||||
stmts: map[string]*sql.Stmt{},
|
closefuncs: make([]func() error, 0),
|
||||||
}
|
}
|
||||||
database.init()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitMysqlDatabase(database *Database, host string, port uint16, user, pass, db string) {
|
func NewMysqlDatabase(host string, port uint16, user, pass, db string) *Database {
|
||||||
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 panicOnNil(database *Database) {
|
func (db *Database) prepare(query string) *sql.Stmt {
|
||||||
if database == nil {
|
s, err := db.db.Prepare(query)
|
||||||
panic("database is nil. initialize database variable with new()")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
panic(fmt.Errorf("compilation failed for query '%s' reason: %w", query, err))
|
panic(err)
|
||||||
}
|
}
|
||||||
db.stmts[query] = stmt
|
db.closefuncs = append(db.closefuncs, s.Close)
|
||||||
return stmt
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) Close() error {
|
func (db *Database) Close() error {
|
||||||
for _, stmt := range db.stmts {
|
for _, close := range db.closefuncs {
|
||||||
stmt.Close()
|
close()
|
||||||
}
|
}
|
||||||
return db.db.Close()
|
return db.db.Close()
|
||||||
}
|
}
|
||||||
|
36
db_test.go
36
db_test.go
@ -9,31 +9,33 @@ 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 ScanUserPkFirst(u *User, encode ScanFunc) error {
|
func UserDecoder(u *User, decode ScanFunc) error {
|
||||||
return encode(&u.Name, &u.Hash, &u.Salt)
|
return decode(&u.Name, &u.Hash, &u.Salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ScanUserPkLast(u *User, encode ScanFunc) error {
|
func InsertUserEncoder(u *User, encode ScanFunc) error {
|
||||||
return encode(&u.Hash, &u.Salt, &u.Name)
|
return encode(u.Name, u.Hash, u.Salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
func UpdateUserByNameEncoder(u *User, encode ScanFunc) error {
|
||||||
InsertUser = Insert(TestDatabase, "INSERT INTO users VALUES (?, ?, ?)", ScanUserPkFirst)
|
return encode(u.Salt, u.Name)
|
||||||
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) {
|
||||||
InitMysqlDatabase(TestDatabase, "ip", 3306, "username", "password", "database")
|
db := NewMysqlDatabase("ip", 3306, "username", "password", "database")
|
||||||
defer TestDatabase.Close()
|
defer db.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{
|
||||||
@ -41,11 +43,13 @@ 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))
|
||||||
|
|
||||||
user := GetUserByName("tordarus")
|
for user := range getUsers("tordarus") {
|
||||||
fmt.Printf("name: \"%s\" | hash: \"%s\" | salt: \"%s\"\n", user.Name, hex.EncodeToString(user.Hash), user.Salt)
|
fmt.Printf("name: \"%s\" | hash: \"%s\" | salt: \"%s\"\n", user.Name, hex.EncodeToString(user.Hash), user.Salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
11
delete.go
11
delete.go
@ -1,11 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,4 @@ 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
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
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
7
go.mod
@ -1,5 +1,8 @@
|
|||||||
module git.milar.in/milarin/advsql
|
module git.tordarus.net/Tordarus/advsql
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require github.com/go-sql-driver/mysql v1.6.0
|
require (
|
||||||
|
git.tordarus.net/Tordarus/adverr v0.2.0
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -1,2 +1,4 @@
|
|||||||
|
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=
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
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] {
|
||||||
prepareGlobal(db, query)
|
s := db.prepare(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
|
||||||
|
@ -10,11 +10,13 @@ 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] {
|
||||||
prepareGlobal(db, query)
|
s, err := db.db.Prepare(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
Normal file
59
stmt.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
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)
|
||||||
|
// }
|
Loading…
x
Reference in New Issue
Block a user