wip: 登录和认证
This commit is contained in:
98
pkg/database/cache/cache.go
vendored
Normal file
98
pkg/database/cache/cache.go
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type encoded_value interface {
|
||||
MarshalBinary() ([]byte, error)
|
||||
}
|
||||
|
||||
type decoded_value interface {
|
||||
UnmarshalBinary(bs []byte) error
|
||||
}
|
||||
|
||||
type Scanner interface {
|
||||
Scan(model any) error
|
||||
}
|
||||
|
||||
type scan struct {
|
||||
err error
|
||||
bs []byte
|
||||
}
|
||||
|
||||
func newScan(bs []byte, err error) *scan {
|
||||
return &scan{bs: bs, err: err}
|
||||
}
|
||||
|
||||
func (s *scan) Scan(model any) error {
|
||||
if s.err != nil {
|
||||
return s.err
|
||||
}
|
||||
|
||||
return unmarshaler(s.bs, model)
|
||||
}
|
||||
|
||||
type Cache interface {
|
||||
Get(ctx context.Context, key string) ([]byte, error)
|
||||
Gets(ctx context.Context, keys ...string) ([][]byte, error)
|
||||
GetScan(ctx context.Context, key string) Scanner
|
||||
GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error)
|
||||
GetExScan(ctx context.Context, key string, duration time.Duration) Scanner
|
||||
// Set value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
Set(ctx context.Context, key string, value any) error
|
||||
Sets(ctx context.Context, vm map[string]any) error
|
||||
// SetEx value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
SetEx(ctx context.Context, key string, value any, duration time.Duration) error
|
||||
Del(ctx context.Context, keys ...string) error
|
||||
GetDel(ctx context.Context, key string) ([]byte, error)
|
||||
GetDelScan(ctx context.Context, key string) Scanner
|
||||
Close()
|
||||
Client() any
|
||||
}
|
||||
|
||||
var (
|
||||
lock = &sync.Mutex{}
|
||||
marshaler func(data any) ([]byte, error) = json.Marshal
|
||||
unmarshaler func(data []byte, model any) error = json.Unmarshal
|
||||
ErrorKeyNotFound = errors.New("key not found")
|
||||
ErrorStoreFailed = errors.New("store failed")
|
||||
Default Cache
|
||||
)
|
||||
|
||||
func handleValue(value any) ([]byte, error) {
|
||||
var (
|
||||
bs []byte
|
||||
err error
|
||||
)
|
||||
|
||||
switch val := value.(type) {
|
||||
case []byte:
|
||||
return val, nil
|
||||
}
|
||||
|
||||
if imp, ok := value.(encoded_value); ok {
|
||||
bs, err = imp.MarshalBinary()
|
||||
} else {
|
||||
bs, err = marshaler(value)
|
||||
}
|
||||
|
||||
return bs, err
|
||||
}
|
||||
|
||||
func SetMarshaler(fn func(data any) ([]byte, error)) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
marshaler = fn
|
||||
}
|
||||
|
||||
func SetUnmarshaler(fn func(data []byte, model any) error) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
unmarshaler = fn
|
||||
}
|
155
pkg/database/cache/memory.go
vendored
Normal file
155
pkg/database/cache/memory.go
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/ristretto/v2"
|
||||
)
|
||||
|
||||
var _ Cache = (*_mem)(nil)
|
||||
|
||||
type _mem struct {
|
||||
ctx context.Context
|
||||
cache *ristretto.Cache[string, []byte]
|
||||
}
|
||||
|
||||
func newMemory(ctx context.Context, ins *ristretto.Cache[string, []byte]) Cache {
|
||||
return &_mem{
|
||||
ctx: ctx,
|
||||
cache: ins,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *_mem) Client() any {
|
||||
return m.cache
|
||||
}
|
||||
|
||||
func (c *_mem) Close() {
|
||||
c.cache.Close()
|
||||
}
|
||||
|
||||
func (c *_mem) Del(ctx context.Context, keys ...string) error {
|
||||
for _, key := range keys {
|
||||
c.cache.Del(key)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *_mem) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
val, ok := c.cache.Get(key)
|
||||
if !ok {
|
||||
return val, ErrorKeyNotFound
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (c *_mem) GetDel(ctx context.Context, key string) ([]byte, error) {
|
||||
val, err := c.Get(ctx, key)
|
||||
if err != nil {
|
||||
return val, err
|
||||
}
|
||||
|
||||
c.cache.Del(key)
|
||||
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (c *_mem) GetDelScan(ctx context.Context, key string) Scanner {
|
||||
val, err := c.GetDel(ctx, key)
|
||||
return newScan(val, err)
|
||||
}
|
||||
|
||||
func (c *_mem) GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error) {
|
||||
val, err := c.Get(ctx, key)
|
||||
if err != nil {
|
||||
return val, err
|
||||
}
|
||||
|
||||
c.cache.SetWithTTL(key, val, 1, duration)
|
||||
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (m *_mem) GetExScan(ctx context.Context, key string, duration time.Duration) Scanner {
|
||||
val, err := m.GetEx(ctx, key, duration)
|
||||
return newScan(val, err)
|
||||
}
|
||||
|
||||
func (m *_mem) GetScan(ctx context.Context, key string) Scanner {
|
||||
val, err := m.Get(ctx, key)
|
||||
return newScan(val, err)
|
||||
}
|
||||
|
||||
func (m *_mem) Gets(ctx context.Context, keys ...string) ([][]byte, error) {
|
||||
vals := make([][]byte, 0, len(keys))
|
||||
|
||||
for _, key := range keys {
|
||||
val, err := m.Get(ctx, key)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrorKeyNotFound) {
|
||||
continue
|
||||
}
|
||||
|
||||
return vals, err
|
||||
}
|
||||
|
||||
vals = append(vals, val)
|
||||
}
|
||||
|
||||
if len(vals) != len(keys) {
|
||||
return vals, ErrorKeyNotFound
|
||||
}
|
||||
|
||||
return vals, nil
|
||||
}
|
||||
|
||||
func (m *_mem) Set(ctx context.Context, key string, value any) error {
|
||||
val, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok := m.cache.Set(key, val, 1); !ok {
|
||||
return ErrorStoreFailed
|
||||
}
|
||||
|
||||
m.cache.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *_mem) SetEx(ctx context.Context, key string, value any, duration time.Duration) error {
|
||||
val, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok := m.cache.SetWithTTL(key, val, 1, duration); !ok {
|
||||
return ErrorStoreFailed
|
||||
}
|
||||
|
||||
m.cache.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *_mem) Sets(ctx context.Context, vm map[string]any) error {
|
||||
for key, value := range vm {
|
||||
val, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok := m.cache.Set(key, val, 1); !ok {
|
||||
return ErrorStoreFailed
|
||||
}
|
||||
}
|
||||
|
||||
m.cache.Wait()
|
||||
|
||||
return nil
|
||||
}
|
84
pkg/database/cache/new.go
vendored
Normal file
84
pkg/database/cache/new.go
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"gitea.loveuer.com/yizhisec/packages/tool"
|
||||
"github.com/dgraph-io/ristretto/v2"
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
func New(opts ...Option) (Cache, error) {
|
||||
var (
|
||||
err error
|
||||
cfg = &option{
|
||||
ctx: context.Background(),
|
||||
}
|
||||
)
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(cfg)
|
||||
}
|
||||
|
||||
if cfg.redis != nil {
|
||||
var (
|
||||
ins *url.URL
|
||||
client *redis.Client
|
||||
)
|
||||
|
||||
if ins, err = url.Parse(*cfg.redis); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
username := ins.User.Username()
|
||||
password, _ := ins.User.Password()
|
||||
|
||||
client = redis.NewClient(&redis.Options{
|
||||
Addr: ins.Host,
|
||||
Username: username,
|
||||
Password: password,
|
||||
})
|
||||
|
||||
if err = client.Ping(tool.CtxTimeout(cfg.ctx, 5)).Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newRedis(cfg.ctx, client), nil
|
||||
}
|
||||
|
||||
if cfg.memory {
|
||||
var (
|
||||
ins *ristretto.Cache[string, []byte]
|
||||
)
|
||||
|
||||
if ins, err = ristretto.NewCache(&ristretto.Config[string, []byte]{
|
||||
NumCounters: 1e7, // number of keys to track frequency of (10M).
|
||||
MaxCost: 1 << 30, // maximum cost of cache (1GB).
|
||||
BufferItems: 64, // number of keys per Get buffer.
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newMemory(cfg.ctx, ins), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid cache option")
|
||||
}
|
||||
|
||||
func Init(opts ...Option) (err error) {
|
||||
opt := &option{}
|
||||
|
||||
for _, optFn := range opts {
|
||||
optFn(opt)
|
||||
}
|
||||
|
||||
if opt.memory {
|
||||
Default, err = New(opts...)
|
||||
return err
|
||||
}
|
||||
|
||||
Default, err = New(opts...)
|
||||
return err
|
||||
}
|
108
pkg/database/cache/new_test.go
vendored
Normal file
108
pkg/database/cache/new_test.go
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
/* if err := Init(WithRedis("127.0.0.1", 6379, "", "MyPassw0rd")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
if err := Default.Set(t.Context(), "zyp:haha", &User{
|
||||
Name: "cache",
|
||||
Age: 18,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := Default.GetDelScan(t.Context(), "zyp:haha")
|
||||
u := new(User)
|
||||
|
||||
if err := s.Scan(u); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("%#v", *u)
|
||||
|
||||
if err := Default.SetEx(t.Context(), "zyp:haha", &User{
|
||||
Name: "redis",
|
||||
Age: 2,
|
||||
}, time.Hour); err != nil {
|
||||
t.Fatal(err)
|
||||
}*/
|
||||
}
|
||||
|
||||
func TestNoAuth(t *testing.T) {
|
||||
//if err := Init(WithRedis("10.125.1.28", 6379, "", "")); err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//
|
||||
//type User struct {
|
||||
// Name string `json:"name"`
|
||||
// Age int `json:"age"`
|
||||
//}
|
||||
//
|
||||
//if err := Default.Set(t.Context(), "zyp:haha", &User{
|
||||
// Name: "cache",
|
||||
// Age: 18,
|
||||
//}); err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//
|
||||
//s := Default.GetDelScan(t.Context(), "zyp:haha")
|
||||
//u := new(User)
|
||||
//
|
||||
//if err := s.Scan(u); err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//
|
||||
//t.Logf("%#v", *u)
|
||||
//
|
||||
//if err := Default.SetEx(t.Context(), "zyp:haha", &User{
|
||||
// Name: "redis",
|
||||
// Age: 2,
|
||||
//}, time.Hour); err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
}
|
||||
|
||||
func TestMemoryDefault(t *testing.T) {
|
||||
if err := Init(WithMemory()); err != nil {
|
||||
t.Fatal("init err:", err)
|
||||
}
|
||||
|
||||
if err := Default.Set(t.Context(), "123", "123"); err != nil {
|
||||
t.Fatal("set err:", err)
|
||||
}
|
||||
|
||||
val, err := Default.Get(t.Context(), "123")
|
||||
if err != nil {
|
||||
t.Fatal("get err:", err)
|
||||
}
|
||||
|
||||
t.Logf("%s", val)
|
||||
}
|
||||
|
||||
func TestMemoryNew(t *testing.T) {
|
||||
client, err := New(WithMemory())
|
||||
if err != nil {
|
||||
t.Fatal("init err:", err)
|
||||
}
|
||||
|
||||
if err := client.Set(t.Context(), "123", "123"); err != nil {
|
||||
t.Fatal("set err:", err)
|
||||
}
|
||||
|
||||
val, err := client.Get(t.Context(), "123")
|
||||
if err != nil {
|
||||
t.Fatal("get err:", err)
|
||||
}
|
||||
|
||||
t.Logf("%s", val)
|
||||
}
|
55
pkg/database/cache/option.go
vendored
Normal file
55
pkg/database/cache/option.go
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type option struct {
|
||||
ctx context.Context
|
||||
redis *string
|
||||
memory bool
|
||||
}
|
||||
|
||||
type Option func(*option)
|
||||
|
||||
func WithCtx(ctx context.Context) Option {
|
||||
return func(c *option) {
|
||||
if ctx != nil {
|
||||
c.ctx = ctx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithRedis(host string, port int, username, password string) Option {
|
||||
return func(c *option) {
|
||||
uri := fmt.Sprintf("redis://%s:%d", host, port)
|
||||
if username != "" || password != "" {
|
||||
uri = fmt.Sprintf("redis://%s:%s@%s:%d", username, password, host, port)
|
||||
}
|
||||
|
||||
c.redis = &uri
|
||||
}
|
||||
}
|
||||
|
||||
func WithRedisURI(uri string) Option {
|
||||
return func(c *option) {
|
||||
ins, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ins.Scheme != "redis" {
|
||||
return
|
||||
}
|
||||
|
||||
c.redis = &uri
|
||||
}
|
||||
}
|
||||
|
||||
func WithMemory() Option {
|
||||
return func(c *option) {
|
||||
c.memory = true
|
||||
}
|
||||
}
|
153
pkg/database/cache/redis.go
vendored
Normal file
153
pkg/database/cache/redis.go
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitea.loveuer.com/yizhisec/packages/tool"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
var _ Cache = (*_redis)(nil)
|
||||
|
||||
type _redis struct {
|
||||
sync.Mutex
|
||||
ctx context.Context
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func (r *_redis) Client() any {
|
||||
return r.client
|
||||
}
|
||||
|
||||
func newRedis(ctx context.Context, client *redis.Client) Cache {
|
||||
r := &_redis{ctx: ctx, client: client}
|
||||
|
||||
go func() {
|
||||
<-r.ctx.Done()
|
||||
if client != nil {
|
||||
r.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *_redis) GetDel(ctx context.Context, key string) ([]byte, error) {
|
||||
s, err := r.client.GetDel(ctx, key).Result()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, ErrorKeyNotFound
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tool.StringToBytes(s), nil
|
||||
}
|
||||
|
||||
func (r *_redis) GetDelScan(ctx context.Context, key string) Scanner {
|
||||
bs, err := r.GetDel(ctx, key)
|
||||
return newScan(bs, err)
|
||||
}
|
||||
|
||||
func (r *_redis) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
result, err := r.client.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, ErrorKeyNotFound
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tool.StringToBytes(result), nil
|
||||
}
|
||||
|
||||
func (r *_redis) Gets(ctx context.Context, keys ...string) ([][]byte, error) {
|
||||
result, err := r.client.MGet(ctx, keys...).Result()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, ErrorKeyNotFound
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tool.Map(
|
||||
result,
|
||||
func(item any, index int) []byte {
|
||||
return tool.StringToBytes(cast.ToString(item))
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func (r *_redis) GetScan(ctx context.Context, key string) Scanner {
|
||||
return newScan(r.Get(ctx, key))
|
||||
}
|
||||
|
||||
func (r *_redis) GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error) {
|
||||
result, err := r.client.GetEx(ctx, key, duration).Result()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, ErrorKeyNotFound
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tool.StringToBytes(result), nil
|
||||
}
|
||||
|
||||
func (r *_redis) GetExScan(ctx context.Context, key string, duration time.Duration) Scanner {
|
||||
return newScan(r.GetEx(ctx, key, duration))
|
||||
}
|
||||
|
||||
func (r *_redis) Set(ctx context.Context, key string, value any) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = r.client.Set(ctx, key, bs, redis.KeepTTL).Result()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *_redis) Sets(ctx context.Context, values map[string]any) error {
|
||||
vm := make(map[string]any)
|
||||
for k, v := range values {
|
||||
bs, err := handleValue(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm[k] = bs
|
||||
}
|
||||
|
||||
return r.client.MSet(ctx, vm).Err()
|
||||
}
|
||||
|
||||
func (r *_redis) SetEx(ctx context.Context, key string, value any, duration time.Duration) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = r.client.SetEX(ctx, key, bs, duration).Result()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *_redis) Del(ctx context.Context, keys ...string) error {
|
||||
return r.client.Del(ctx, keys...).Err()
|
||||
}
|
||||
|
||||
func (r *_redis) Close() {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
_ = r.client.Close()
|
||||
r.client = nil
|
||||
}
|
49
pkg/database/db/db.go
Normal file
49
pkg/database/db/db.go
Normal file
@ -0,0 +1,49 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Debug bool
|
||||
DryRun bool
|
||||
}
|
||||
|
||||
type DB interface {
|
||||
Session(ctx context.Context, configs ...Config) *gorm.DB
|
||||
}
|
||||
|
||||
type db struct {
|
||||
tx *gorm.DB
|
||||
}
|
||||
|
||||
var (
|
||||
Default DB
|
||||
)
|
||||
|
||||
func (db *db) Session(ctx context.Context, configs ...Config) *gorm.DB {
|
||||
var (
|
||||
sc = &gorm.Session{Context: ctx}
|
||||
session *gorm.DB
|
||||
)
|
||||
|
||||
if len(configs) == 0 {
|
||||
session = db.tx.Session(sc)
|
||||
return session
|
||||
}
|
||||
|
||||
cfg := configs[0]
|
||||
|
||||
if cfg.DryRun {
|
||||
sc.DryRun = true
|
||||
}
|
||||
|
||||
session = db.tx.Session(sc)
|
||||
|
||||
if cfg.Debug {
|
||||
session = session.Debug()
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
48
pkg/database/db/new.go
Normal file
48
pkg/database/db/new.go
Normal file
@ -0,0 +1,48 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var defaultSqlite = "data.db"
|
||||
|
||||
func New(opts ...OptionFn) (DB, error) {
|
||||
var (
|
||||
err error
|
||||
conf = &config{
|
||||
sqlite: &defaultSqlite,
|
||||
}
|
||||
tx *gorm.DB
|
||||
)
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(conf)
|
||||
}
|
||||
|
||||
if conf.mysql != nil {
|
||||
tx, err = gorm.Open(mysql.Open(*conf.mysql))
|
||||
goto CHECK
|
||||
}
|
||||
|
||||
if conf.pg != nil {
|
||||
tx, err = gorm.Open(postgres.Open(*conf.pg))
|
||||
goto CHECK
|
||||
}
|
||||
|
||||
tx, err = gorm.Open(sqlite.Open(*conf.sqlite))
|
||||
|
||||
CHECK:
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &db{tx: tx}, nil
|
||||
}
|
||||
|
||||
func Init(opts ...OptionFn) (err error) {
|
||||
Default, err = New(opts...)
|
||||
return err
|
||||
}
|
25
pkg/database/db/new_test.go
Normal file
25
pkg/database/db/new_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
//mdb, err := New(WithMysql("127.0.0.1", 3306, "root", "MyPassw0rd", "mydb"))
|
||||
//if err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//
|
||||
//type User struct {
|
||||
// Id uint64 `gorm:"primaryKey"`
|
||||
// Username string `gorm:"unique"`
|
||||
//}
|
||||
//
|
||||
//if err = mdb.Session(t.Context()).AutoMigrate(&User{}); err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//
|
||||
//if err = mdb.Session(t.Context()).Create(&User{Username: "zyp"}).Error; err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
}
|
45
pkg/database/db/option.go
Normal file
45
pkg/database/db/option.go
Normal file
@ -0,0 +1,45 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
ctx context.Context
|
||||
mysql *string
|
||||
pg *string
|
||||
sqlite *string
|
||||
}
|
||||
|
||||
type OptionFn func(*config)
|
||||
|
||||
func WithCtx(ctx context.Context) OptionFn {
|
||||
return func(c *config) {
|
||||
if ctx != nil {
|
||||
c.ctx = ctx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithMysql(host string, port int, user string, password string, database string) OptionFn {
|
||||
return func(c *config) {
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, password, host, port, database)
|
||||
c.mysql = &dsn
|
||||
}
|
||||
}
|
||||
|
||||
func WithPg(host string, port int, user string, password string, database string) OptionFn {
|
||||
return func(c *config) {
|
||||
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=disable TimeZone=Asia/Shanghai", host, user, password, database, port)
|
||||
c.pg = &dsn
|
||||
}
|
||||
}
|
||||
|
||||
func WithSqlite(path string) OptionFn {
|
||||
return func(c *config) {
|
||||
if path != "" {
|
||||
c.sqlite = &path
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user