Compare commits
5 Commits
geoip/v1.1
...
entgo/v1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d39ab89d9 | ||
|
|
902a0ce860 | ||
|
|
576d1bfe2b | ||
|
|
4e084cc4b5 | ||
|
|
ce853c6b87 |
@@ -1,11 +1,18 @@
|
||||
package entgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
|
||||
|
||||
"github.com/XSAM/otelsql"
|
||||
|
||||
entSql "entgo.io/ent/dialect/sql"
|
||||
)
|
||||
|
||||
type entClientInterface interface {
|
||||
@@ -14,10 +21,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,28 +35,85 @@ 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()
|
||||
}
|
||||
|
||||
// Close 关闭数据库连接
|
||||
func (c *EntClient[T]) Close() error {
|
||||
return c.db.Close()
|
||||
}
|
||||
|
||||
// Query 查询数据
|
||||
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)
|
||||
}
|
||||
|
||||
// SetConnectionOption 设置连接配置
|
||||
func (c *EntClient[T]) SetConnectionOption(maxIdleConnections, maxOpenConnections int, connMaxLifetime time.Duration) {
|
||||
// 连接池中最多保留的空闲连接数量
|
||||
c.DB().SetMaxIdleConns(maxIdleConnections)
|
||||
// 连接池在同一时间打开连接的最大数量
|
||||
c.DB().SetMaxOpenConns(maxOpenConnections)
|
||||
// 连接可重用的最大时间长度
|
||||
c.DB().SetConnMaxLifetime(connMaxLifetime)
|
||||
}
|
||||
|
||||
func driverNameToSemConvKeyValue(driverName string) attribute.KeyValue {
|
||||
switch driverName {
|
||||
case "mariadb":
|
||||
return semconv.DBSystemMariaDB
|
||||
case "mysql":
|
||||
return semconv.DBSystemMySQL
|
||||
case "postgresql":
|
||||
return semconv.DBSystemPostgreSQL
|
||||
case "sqlite":
|
||||
return semconv.DBSystemSqlite
|
||||
default:
|
||||
return semconv.DBSystemKey.String(driverName)
|
||||
}
|
||||
}
|
||||
|
||||
// CreateDriver 创建数据库驱动
|
||||
func CreateDriver(driverName, dsn string, maxIdleConnections, maxOpenConnections int, connMaxLifetime time.Duration) (*sql.Driver, error) {
|
||||
drv, err := sql.Open(driverName, dsn)
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("failed opening connection to db: %v", err))
|
||||
func CreateDriver(driverName, dsn string, enableTrace, enableMetrics bool) (*entSql.Driver, error) {
|
||||
var db *sql.DB
|
||||
var drv *entSql.Driver
|
||||
var err error
|
||||
|
||||
if enableTrace {
|
||||
// Connect to database
|
||||
if db, err = otelsql.Open(driverName, dsn, otelsql.WithAttributes(
|
||||
driverNameToSemConvKeyValue(driverName),
|
||||
)); err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("failed opening connection to db: %v", err))
|
||||
}
|
||||
|
||||
drv = entSql.OpenDB(driverName, db)
|
||||
} else {
|
||||
if drv, err = entSql.Open(driverName, dsn); err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("failed opening connection to db: %v", err))
|
||||
}
|
||||
|
||||
db = drv.DB()
|
||||
}
|
||||
|
||||
db := drv.DB()
|
||||
// 连接池中最多保留的空闲连接数量
|
||||
db.SetMaxIdleConns(maxIdleConnections)
|
||||
// 连接池在同一时间打开连接的最大数量
|
||||
db.SetMaxOpenConns(maxOpenConnections)
|
||||
// 连接可重用的最大时间长度
|
||||
db.SetConnMaxLifetime(connMaxLifetime)
|
||||
// Register DB stats to meter
|
||||
if enableMetrics {
|
||||
err = otelsql.RegisterDBStatsMetrics(db, otelsql.WithAttributes(
|
||||
driverNameToSemConvKeyValue(driverName),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("failed register otel meter: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
return drv, nil
|
||||
}
|
||||
|
||||
12
entgo/go.mod
12
entgo/go.mod
@@ -5,20 +5,23 @@ go 1.21
|
||||
toolchain go1.22.1
|
||||
|
||||
require (
|
||||
entgo.io/contrib v0.4.5
|
||||
entgo.io/contrib v0.5.0
|
||||
entgo.io/ent v0.13.1
|
||||
github.com/go-kratos/kratos/v2 v2.7.3
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tx7do/go-utils v1.1.9
|
||||
github.com/tx7do/go-utils v1.1.11
|
||||
)
|
||||
|
||||
require (
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect
|
||||
github.com/XSAM/otelsql v0.30.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/bufbuild/protocompile v0.6.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
@@ -29,10 +32,13 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/sony/sonyflake v1.2.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.1 // indirect
|
||||
go.opentelemetry.io/otel v1.26.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.26.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.26.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/mod v0.15.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.18.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
21
entgo/go.sum
21
entgo/go.sum
@@ -1,11 +1,13 @@
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 h1:GwdJbXydHCYPedeeLt4x/lrlIISQ4JTH1mRWuE5ZZ14=
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43/go.mod h1:uj3pm+hUTVN/X5yfdBexHlZv+1Xu5u5ZbZx7+CDavNU=
|
||||
entgo.io/contrib v0.4.5 h1:BFaOHwFLE8WZjVJadP0XHCIaxgcC1BAtUvAyw7M/GHk=
|
||||
entgo.io/contrib v0.4.5/go.mod h1:wpZyq2DJgthugFvDBlaqMXj9mV4/9ebyGEn7xlTVQqE=
|
||||
entgo.io/contrib v0.5.0 h1:M4IqodImfUm327RDwNAITLNz3PsxVeC3rD4DPeVA8Gs=
|
||||
entgo.io/contrib v0.5.0/go.mod h1:q8dXQCmzqpSlVdT2bWDydjgznGcy3y4zmsYmVFC9V/U=
|
||||
entgo.io/ent v0.13.1 h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=
|
||||
entgo.io/ent v0.13.1/go.mod h1:qCEmo+biw3ccBn9OyL4ZK5dfpwg++l1Gxwac5B1206A=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/XSAM/otelsql v0.30.0 h1:yd6Ds3xQkKtP5+JztH2un5Hfy9uyo1eUgv34dGpSIK4=
|
||||
github.com/XSAM/otelsql v0.30.0/go.mod h1:12ObuENPHhAcc2cU89u7Yr0uT60+FliFCTP9Sd4N68o=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
|
||||
@@ -16,6 +18,11 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-kratos/kratos/v2 v2.7.3 h1:T9MS69qk4/HkVUuHw5GS9PDVnOfzn+kxyF0CL5StqxA=
|
||||
github.com/go-kratos/kratos/v2 v2.7.3/go.mod h1:CQZ7V0qyVPwrotIpS5VNNUJNzEbcyRUl5pRtxLOIvn4=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
@@ -56,6 +63,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA=
|
||||
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
|
||||
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
|
||||
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
|
||||
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
|
||||
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
|
||||
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||
@@ -66,8 +79,8 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
53
gorm/go.mod
Normal file
53
gorm/go.mod
Normal file
@@ -0,0 +1,53 @@
|
||||
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
|
||||
gorm.io/plugin/opentelemetry v0.1.4
|
||||
)
|
||||
|
||||
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-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // 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.25.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.25.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.25.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.25.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/tx7do/go-utils => ../
|
||||
2940
gorm/go.sum
Normal file
2940
gorm/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
90
gorm/gorm_client.go
Normal file
90
gorm/gorm_client.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package gorm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gorm.io/plugin/opentelemetry/tracing"
|
||||
|
||||
"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, enableTrace, enableMetrics bool, gormCfg *gorm.Config) *Client {
|
||||
c := &Client{}
|
||||
|
||||
if gormCfg == nil {
|
||||
gormCfg = &gorm.Config{}
|
||||
}
|
||||
|
||||
c.err = c.createGormClient(driverName, dsn, enableMigrate, enableTrace, enableMetrics, gormCfg)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) Error() error {
|
||||
return c.err
|
||||
}
|
||||
|
||||
// createGormClient 创建GORM的客户端
|
||||
func (c *Client) createGormClient(driverName, dsn string, enableMigrate, enableTrace, enableMetrics 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 enableTrace {
|
||||
var opts []tracing.Option
|
||||
if enableMetrics {
|
||||
opts = append(opts, tracing.WithoutMetrics())
|
||||
}
|
||||
|
||||
if err = client.Use(tracing.NewPlugin(opts...)); 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
13
gorm/migrates.go
Normal 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
134
math/gaussian.go
Normal 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
47
math/gaussian_test.go
Normal 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
44
math/math.go
Normal 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
30
math/math_test.go
Normal 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)
|
||||
}
|
||||
7
tag.bat
7
tag.bat
@@ -1,6 +1,9 @@
|
||||
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.14
|
||||
git tag gorm/v1.1.1
|
||||
|
||||
git push origin --tags
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user