
Research
Security News
The Growing Risk of Malicious Browser Extensions
Socket researchers uncover how browser extensions in trusted stores are used to hijack sessions, redirect traffic, and manipulate user behavior.
github.com/brianleishman/cool-mysql
cool-mysql
is a small library that wraps Go's database/sql
with MySQL oriented helpers. It keeps the underlying interfaces intact while providing conveniences that save you time when writing data access code.
@@name
tokensmax_allowed_packet
string
, time.Time
)log/slog
by default with a Zap adaptergo get github.com/StirlingMarketingGroup/cool-mysql
package main
import (
"log"
"time"
mysql "github.com/StirlingMarketingGroup/cool-mysql"
)
type User struct {
ID int `db:"id"`
Name string `db:"name"`
}
func main() {
db, err := mysql.New(
"writeUser", "writePass", "mydb", "127.0.0.1", 3306,
"readUser", "readPass", "mydb", "127.0.0.1", 3306,
"utf8mb4_unicode_ci", time.Local,
)
if err != nil {
log.Fatal(err)
}
var users []User
err = db.Select(&users,
"SELECT id, name FROM users WHERE created_at > @@since",
time.Minute, // cache TTL when caching is configured
mysql.Params{"since": time.Now().Add(-24 * time.Hour)},
)
if err != nil {
log.Fatal(err)
}
log.Printf("loaded %d users", len(users))
}
// use Redis
r := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
db.EnableRedis(r)
// or Memcached
db.EnableMemcache(memcache.New("localhost:11211"))
// or a simple in-memory cache using weak pointers
db.UseCache(mysql.NewWeakCache())
// caches can be stacked
db.UseCache(mysql.NewMultiCache(mysql.NewWeakCache(), mysql.NewRedisCache(r)))
type Profile struct {
Likes []string `json:"likes"`
}
type User struct {
ID int
Name string
Profile Profile `db:"profile_json"`
}
var u User
err := db.Select(&u,
"SELECT id, name, profile_json FROM users WHERE id=@@id",
0,
mysql.Params{"id": 1},
)
if err != nil {
// if no row is returned, err == sql.ErrNoRows
log.Fatal(err)
}
Selecting into a slice never returns sql.ErrNoRows
if empty:
var all []User
err := db.Select(&all, "SELECT * FROM users WHERE active=1", 0)
if err != nil {
log.Fatal(err)
}
log.Println(len(all))
var name string
err := db.Select(&name, "SELECT name FROM users WHERE id=@@id", 0, 5) // single param value
userCh := make(chan User)
go func() {
defer close(userCh)
if err := db.Select(userCh, "SELECT id, name FROM users", 0); err != nil {
log.Fatal(err)
}
}()
for u := range userCh {
log.Printf("%d: %s", u.ID, u.Name)
}
err = db.Select(func(u User) {
log.Printf("found %s", u.Name)
}, "SELECT id, name FROM users WHERE active=1", 0)
var since *time.Time
query := `SELECT id, name FROM users WHERE 1=1 {{ if .since }}AND created_at > @@since{{ end }}`
err = db.Select(&users, query, 0, mysql.Params{"since": since})
newUser := User{ID: 123, Name: "Alice"}
err = db.Insert("users", newUser) // query is built automatically
The source can also be a channel of structs for batch inserts.
ch := make(chan User)
go func() {
for _, u := range users {
ch <- u
}
close(ch)
}()
if err := db.Insert("users", ch); err != nil { // batch insert
log.Fatal(err)
}
up := User{ID: 123, Name: "Alice"}
err = db.Upsert(
"users", // table name only
[]string{"id"}, // unique columns
[]string{"name"}, // columns to update on conflict
"", // additional WHERE clause
up,
)
Fields in a struct can include a mysql
tag to control how they map to the database. The tag name overrides the column name used by the insert and upsert helpers and when scanning query results. One option modifies how zero values are marshaled:
defaultzero
– write default(column)
instead of the zero value.This option is also honored when a struct is passed to InterpolateParams
.
type Person struct {
ID int `mysql:"id"`
Name string `mysql:"name,defaultzero"`
}
db.Insert("people", Person{}) // name becomes default(`name`)
_, _, _ = mysql.InterpolateParams(
"SELECT * FROM people WHERE name = @@Name",
Person{},
) // produces: SELECT * FROM people WHERE name = default(`name`)
tmpl := `SELECT * FROM people {{ if .Name }}WHERE name=@@Name{{ end }}`
When using template syntax the struct field name (.Name
above) is used for
lookups, not the column name from the mysql
tag.
tx, commit, cancel, err := mysql.GetOrCreateTxFromContext(ctx)
defer cancel()
if err != nil {
return fmt.Errorf("failed to create transaction: %w", err)
}
ctx = mysql.NewContextWithTx(ctx, tx)
// do DB work with tx in context
if err := commit(); err != nil {
return fmt.Errorf("failed to commit tx: %w", err)
}
This project is licensed under the MIT License.
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover how browser extensions in trusted stores are used to hijack sessions, redirect traffic, and manipulate user behavior.
Research
Security News
An in-depth analysis of credential stealers, crypto drainers, cryptojackers, and clipboard hijackers abusing open source package registries to compromise Web3 development environments.
Security News
pnpm 10.12.1 introduces a global virtual store for faster installs and new options for managing dependencies with version catalogs.