Compare commits

...

4 Commits

Author SHA1 Message Date
tx7do
902a0ce860 feat: add gorm utils. 2024-04-28 19:02:42 +08:00
tx7do
576d1bfe2b feat: add math utils. 2024-04-28 09:42:53 +08:00
tx7do
4e084cc4b5 feat: TimestamppbToTime & TimeToTimestamppb. 2024-04-21 22:20:59 +08:00
tx7do
ce853c6b87 feat: entgo interface. 2024-04-16 18:43:49 +08:00
11 changed files with 3363 additions and 10 deletions

View File

@@ -1,11 +1,13 @@
package entgo
import (
"context"
"database/sql"
"errors"
"fmt"
"time"
"entgo.io/ent/dialect/sql"
entSql "entgo.io/ent/dialect/sql"
)
type entClientInterface interface {
@@ -14,10 +16,10 @@ type entClientInterface interface {
type EntClient[T entClientInterface] struct {
db T
drv *sql.Driver
drv *entSql.Driver
}
func NewEntClient[T entClientInterface](db T, drv *sql.Driver) *EntClient[T] {
func NewEntClient[T entClientInterface](db T, drv *entSql.Driver) *EntClient[T] {
return &EntClient[T]{
db: db,
drv: drv,
@@ -28,17 +30,29 @@ func (c *EntClient[T]) Client() T {
return c.db
}
func (c *EntClient[T]) Driver() *sql.Driver {
func (c *EntClient[T]) Driver() *entSql.Driver {
return c.drv
}
func (c *EntClient[T]) Close() {
_ = c.db.Close()
func (c *EntClient[T]) DB() *sql.DB {
return c.drv.DB()
}
func (c *EntClient[T]) Close() error {
return c.db.Close()
}
func (c *EntClient[T]) Query(ctx context.Context, query string, args, v any) error {
return c.Driver().Query(ctx, query, args, v)
}
func (c *EntClient[T]) Exec(ctx context.Context, query string, args, v any) error {
return c.Driver().Exec(ctx, query, args, v)
}
// CreateDriver 创建数据库驱动
func CreateDriver(driverName, dsn string, maxIdleConnections, maxOpenConnections int, connMaxLifetime time.Duration) (*sql.Driver, error) {
drv, err := sql.Open(driverName, dsn)
func CreateDriver(driverName, dsn string, maxIdleConnections, maxOpenConnections int, connMaxLifetime time.Duration) (*entSql.Driver, error) {
drv, err := entSql.Open(driverName, dsn)
if err != nil {
return nil, errors.New(fmt.Sprintf("failed opening connection to db: %v", err))
}

48
gorm/go.mod Normal file
View File

@@ -0,0 +1,48 @@
module github.com/tx7do/go-utils/gorm
go 1.21
toolchain go1.22.1
require (
gorm.io/driver/clickhouse v0.6.0
gorm.io/driver/mysql v1.5.6
gorm.io/driver/postgres v1.5.7
gorm.io/driver/sqlite v1.5.5
gorm.io/driver/sqlserver v1.5.3
gorm.io/gorm v1.25.10
)
require (
github.com/ClickHouse/ch-go v0.58.2 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.15.0 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.6.1 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.4.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/microsoft/go-mssqldb v1.6.0 // indirect
github.com/paulmach/orb v0.10.0 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/tx7do/go-utils => ../

2926
gorm/go.sum Normal file

File diff suppressed because it is too large Load Diff

77
gorm/gorm_client.go Normal file
View File

@@ -0,0 +1,77 @@
package gorm
import (
"fmt"
"gorm.io/gorm"
"gorm.io/driver/clickhouse"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/driver/sqlserver"
)
type Client struct {
*gorm.DB
err error
}
func NewClient(driverName, dsn string, enableMigrate bool, gormCfg *gorm.Config) *Client {
c := &Client{}
if gormCfg == nil {
gormCfg = &gorm.Config{}
}
c.err = c.createGormClient(driverName, dsn, enableMigrate, gormCfg)
return c
}
func (c *Client) Error() error {
return c.err
}
// createGormClient 创建GORM的客户端
func (c *Client) createGormClient(driverName, dsn string, enableMigrate bool, gormCfg *gorm.Config) error {
var driver gorm.Dialector
switch driverName {
default:
fallthrough
case "mysql":
driver = mysql.Open(dsn)
break
case "postgres":
driver = postgres.Open(dsn)
break
case "clickhouse":
driver = clickhouse.Open(dsn)
break
case "sqlite":
driver = sqlite.Open(dsn)
break
case "sqlserver":
driver = sqlserver.Open(dsn)
break
}
client, err := gorm.Open(driver, gormCfg)
if err != nil {
return fmt.Errorf("failed opening connection to db: %v", err)
}
// 运行数据库迁移工具
if enableMigrate {
if err = client.AutoMigrate(
getMigrateModels()...,
); err != nil {
return fmt.Errorf("failed creating schema resources: %v", err)
}
}
c.DB = client
return nil
}

13
gorm/migrates.go Normal file
View File

@@ -0,0 +1,13 @@
package gorm
var migrateModels []interface{}
// RegisterMigrateModel 注册用于数据库迁移的数据库模型
func RegisterMigrateModel(model interface{}) {
migrateModels = append(migrateModels, &model)
}
// getMigrateModels 获取用于数据库迁移的数据库模型
func getMigrateModels() []interface{} {
return migrateModels
}

134
math/gaussian.go Normal file
View File

@@ -0,0 +1,134 @@
package math
import (
"math"
)
// prop
//mean: the mean (μ) of the distribution
//variance: the variance (σ^2) of the distribution
//standardDeviation: the standard deviation (σ) of the distribution
// combination
type Gaussian struct {
mean float64
variance float64
standardDeviation float64
}
func NewGaussian(mean, variance float64) *Gaussian {
if variance <= 0.0 {
panic("error")
}
return &Gaussian{
mean: mean,
variance: variance,
standardDeviation: math.Sqrt(float64(variance)),
}
}
// Erfc Complementary error function
// From Numerical Recipes in C 2e p221
func Erfc(x float64) float64 {
z := math.Abs(x)
t := 1 / (1 + z/2)
r := t * math.Exp(-z*z-1.26551223+t*(1.00002368+
t*(0.37409196+t*(0.09678418+t*(-0.18628806+
t*(0.27886807+t*(-1.13520398+t*(1.48851587+
t*(-0.82215223+t*0.17087277)))))))))
if x >= 0 {
return r
} else {
return 2 - r
}
}
// Ierfc Inverse complementary error function
// From Numerical Recipes 3e p265
func Ierfc(x float64) float64 {
if x >= 2 {
return -100
}
if x <= 0 {
return 100
}
var xx float64
if x < 1 {
xx = x
} else {
xx = 2 - x
}
t := math.Sqrt(-2 * math.Log(xx/2))
r := -0.70711 * ((2.30753+t*0.27061)/
(1+t*(0.99229+t*0.04481)) - t)
for j := 0; j < 2; j++ {
e := Erfc(r) - xx
r += e / (1.12837916709551257*math.Exp(-(r*r)) - r*e)
}
if x < 1 {
return r
} else {
return -r
}
}
// fromPrecisionMean Construct a new distribution from the precision and precisionmean
func fromPrecisionMean(precision, precisionmean float64) *Gaussian {
return NewGaussian(precisionmean/precision, 1/precision)
}
/// PROB
// Pdf pdf(x): the probability density function, which describes the probability
// of a random variable taking on the value x
func (g *Gaussian) Pdf(x float64) float64 {
m := g.standardDeviation * math.Sqrt(2*math.Pi)
e := math.Exp(-math.Pow(x-g.mean, 2) / (2 * g.variance))
return e / m
}
// Cdf cdf(x): the cumulative distribution function,
// which describes the probability of a random
// variable falling in the interval (−∞, x]
func (g *Gaussian) Cdf(x float64) float64 {
return 0.5 * Erfc(-(x-g.mean)/(g.standardDeviation*math.Sqrt(2)))
}
// Ppf ppf(x): the percent point function, the inverse of cdf
func (g *Gaussian) Ppf(x float64) float64 {
return g.mean - g.standardDeviation*math.Sqrt(2)*Ierfc(2*x)
}
// Add add(d): returns the result of adding this and the given distribution
func (g *Gaussian) Add(d *Gaussian) *Gaussian {
return NewGaussian(g.mean+d.mean, g.variance+d.variance)
}
// Sub sub(d): returns the result of subtracting this and the given distribution
func (g *Gaussian) Sub(d *Gaussian) *Gaussian {
return NewGaussian(g.mean-d.mean, g.variance+d.variance)
}
// Scale scale(c): returns the result of scaling this distribution by the given constant
func (g *Gaussian) Scale(c float64) *Gaussian {
return NewGaussian(g.mean*c, g.variance*c*c)
}
// Mul mul(d): returns the product distribution of this and the given distribution. If a constant is passed in the distribution is scaled.
func (g *Gaussian) Mul(d *Gaussian) *Gaussian {
precision := 1 / g.variance
dprecision := 1 / d.variance
return fromPrecisionMean(precision+dprecision, precision*g.mean+dprecision*d.mean)
}
// Div div(d): returns the quotient distribution of this and the given distribution. If a constant is passed in the distribution is scaled by 1/d.
func (g *Gaussian) Div(d *Gaussian) *Gaussian {
precision := 1 / g.variance
dprecision := 1 / d.variance
return fromPrecisionMean(precision-dprecision, precision*g.mean-dprecision*d.mean)
}

47
math/gaussian_test.go Normal file
View File

@@ -0,0 +1,47 @@
package math
import (
"fmt"
"testing"
)
func TestGaussian(t *testing.T) {
g := NewGaussian(3.0, 1)
fmt.Printf("g: %#v\n", g)
fmt.Printf("pdf: %f\n", g.Pdf(5))
fmt.Printf("cdf: %f\n", g.Cdf(2))
fmt.Printf("ppf: %f\n", g.Ppf(5))
d := NewGaussian(0, 1)
fmt.Printf("ppf: %f, %f\n", d.Pdf(-2), 0.053991)
fmt.Printf("ppf: %f, %f\n", d.Pdf(-1), 0.241971)
fmt.Printf("ppf: %f, %f\n", d.Pdf(0), 0.398942)
fmt.Printf("ppf: %f, %f\n", d.Pdf(1), 0.241971)
fmt.Printf("ppf: %f, %f\n", d.Pdf(2), 0.053991)
fmt.Printf("cdf: %f, %f\n", d.Cdf(-1.28155), 0.1)
fmt.Printf("cdf: %f, %f\n", d.Cdf(-0.67499), 0.25)
fmt.Printf("cdf: %f, %f\n", d.Cdf(0), 0.5)
fmt.Printf("cdf: %f, %f\n", d.Cdf(0.67499), 0.75)
fmt.Printf("cdf: %f, %f\n", d.Cdf(1.28155), 0.9)
fmt.Printf("ppf: %f, %f\n", d.Ppf(0.1), -1.28155)
fmt.Printf("ppf: %f, %f\n", d.Ppf(0.25), -0.67499)
fmt.Printf("ppf: %f, %f\n", d.Ppf(0.5), 0.0)
fmt.Printf("ppf: %f, %f\n", d.Ppf(0.75), 0.67449)
fmt.Printf("ppf: %f, %f\n", d.Ppf(0.9), 1.28155)
d = d.Mul(NewGaussian(0, 1))
fmt.Printf("Mul: %#v\n", d)
fmt.Printf("%#v\n%#v", NewGaussian(1, 1).Scale(2), NewGaussian(2, 4))
d = NewGaussian(1, 1).Div(NewGaussian(1, 2))
fmt.Printf("div\n")
fmt.Printf("%#v\n%#v\n", d, NewGaussian(1, 2))
fmt.Printf("%#v\n%#v\n", NewGaussian(1, 1).Scale(1/(1.0/2.0)), NewGaussian(2, 4))
fmt.Printf("ADD:\n%#v\n%#v\n", NewGaussian(1, 1).Add(NewGaussian(1, 2)), NewGaussian(2, 3))
fmt.Printf("SUB:\n%#v\n%#v\n", NewGaussian(1, 1).Sub(NewGaussian(1, 2)), NewGaussian(0, 3))
fmt.Printf("SCALE:\n%#v\n%#v\n", NewGaussian(1, 1).Scale(2), NewGaussian(2, 4))
}

44
math/math.go Normal file
View File

@@ -0,0 +1,44 @@
package math
import (
"math"
)
// Sign 符号函数Sign function简称sgn是一个逻辑函数用以判断实数的正负号。为避免和英文读音相似的正弦函数sine混淆它亦称为Signum function。
func Sign[T int | int8 | int16 | int32 | int64 | float32 | float64](x T) T {
switch {
case x < 0: // x < 0 : -1
return -1
case x > 0: // x > 0 : +1
return +1
default: // x == 0 : 0
return 0
}
}
// Mean 计算给定数据的平均值
func Mean(num []float64) float64 {
var count = len(num)
var sum float64 = 0
for i := 0; i < count; i++ {
sum += num[i]
}
return sum / float64(count)
}
// Variance 使用平均值计算给定数据的方差
func Variance(mean float64, num []float64) float64 {
var count = len(num)
var variance float64 = 0
for i := 0; i < count; i++ {
variance += math.Pow(num[i]-mean, 2)
}
return variance / float64(count)
}
// StandardDeviation 使用方差计算给定数据的标准偏差
func StandardDeviation(num []float64) float64 {
var mean = Mean(num)
var variance = Variance(mean, num)
return math.Sqrt(variance)
}

30
math/math_test.go Normal file
View File

@@ -0,0 +1,30 @@
package math
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSign(t *testing.T) {
assert.True(t, Sign(2) == 1)
assert.True(t, Sign(-2) == -1)
assert.True(t, Sign(0) == 0)
assert.True(t, Sign(int64(2)) == 1)
assert.True(t, Sign(int64(-2)) == -1)
assert.True(t, Sign(int64(0)) == 0)
assert.True(t, Sign(float32(2)) == 1)
assert.True(t, Sign(float32(-2)) == -1)
assert.True(t, Sign(float32(0)) == 0)
assert.True(t, Sign(float64(2)) == 1)
assert.True(t, Sign(float64(-2)) == -1)
assert.True(t, Sign(float64(0)) == 0)
}
func TestStandardDeviation(t *testing.T) {
assert.Equal(t, StandardDeviation([]float64{3, 5, 9, 1, 8, 6, 58, 9, 4, 10}), 15.8117045254457)
assert.Equal(t, StandardDeviation([]float64{1, 3, 5, 7, 9, 11, 2, 4, 6, 8}), 3.0397368307141326)
}

View File

@@ -1,6 +1,8 @@
git tag v1.1.9
git tag v1.1.11
git tag bank_card/v1.1.1
git tag entgo/v1.1.12
git tag geoip/v1.1.1
git tag entgo/v1.1.13
git tag gorm/v1.1.0
git push origin --tags

View File

@@ -3,6 +3,8 @@ package util
import (
"time"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/tx7do/go-utils/trans"
)
@@ -114,3 +116,19 @@ func TimeToDateString(tm *time.Time) *string {
}
return trans.String(tm.Format(DateLayout))
}
// TimestamppbToTime timestamppb.Timestamp -> time.Time
func TimestamppbToTime(tm *timestamppb.Timestamp) *time.Time {
if tm != nil {
return trans.Ptr(tm.AsTime())
}
return nil
}
// TimeToTimestamppb time.Time -> timestamppb.Timestamp
func TimeToTimestamppb(tm *time.Time) *timestamppb.Timestamp {
if tm != nil {
return timestamppb.New(*tm)
}
return nil
}