Compare commits

..

11 Commits

Author SHA1 Message Date
Bobo
fdcb900700 feat: entgo 2025-02-08 16:00:54 +08:00
Bobo
ce04468424 feat: entgo. 2025-02-08 15:31:39 +08:00
Bobo
d1418caf84 feat: entgo. 2025-02-08 14:44:21 +08:00
Bobo
f73f016ec5 feat: entgo. 2025-02-08 00:08:10 +08:00
Bobo
d549d305ae feat: entgo. 2025-02-08 00:00:50 +08:00
Bobo
23dcad60a3 feat: time utils. 2025-02-07 22:42:19 +08:00
Bobo
fa7ae4f876 feat: time trans. 2025-01-11 13:22:23 +08:00
tx7do
9f6a4eba80 feat: ent support update json field. 2024-12-14 14:41:44 +08:00
tx7do
801deb98cd feat: ent support update json field. 2024-12-14 13:07:01 +08:00
tx7do
c9a0909d46 feat: upgrade go.mod. 2024-11-14 11:20:41 +08:00
tx7do
9be498db69 feat: upgrade go.mod. 2024-11-14 11:18:05 +08:00
20 changed files with 395 additions and 140 deletions

View File

@@ -15,16 +15,16 @@ import (
entSql "entgo.io/ent/dialect/sql"
)
type entClientInterface interface {
type EntClientInterface interface {
Close() error
}
type EntClient[T entClientInterface] struct {
type EntClient[T EntClientInterface] struct {
db T
drv *entSql.Driver
}
func NewEntClient[T entClientInterface](db T, drv *entSql.Driver) *EntClient[T] {
func NewEntClient[T EntClientInterface](db T, drv *entSql.Driver) *EntClient[T] {
return &EntClient[T]{
db: db,
drv: drv,

View File

@@ -8,15 +8,16 @@ require (
entgo.io/contrib v0.6.0
entgo.io/ent v0.14.1
github.com/XSAM/otelsql v0.35.0
github.com/go-kratos/kratos/v2 v2.8.1
github.com/go-kratos/kratos/v2 v2.8.2
github.com/google/uuid v1.6.0
github.com/stretchr/testify v1.9.0
github.com/tx7do/go-utils v1.1.12
go.opentelemetry.io/otel v1.31.0
github.com/stretchr/testify v1.10.0
github.com/tx7do/go-utils v1.1.13
go.opentelemetry.io/otel v1.33.0
google.golang.org/protobuf v1.35.2
)
require (
ariga.io/atlas v0.28.1 // indirect
ariga.io/atlas v0.29.0 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect
@@ -27,21 +28,21 @@ require (
github.com/go-openapi/inflect v0.21.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/hashicorp/hcl/v2 v2.22.0 // indirect
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
github.com/jhump/protoreflect v1.17.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sony/sonyflake v1.2.0 // indirect
github.com/zclconf/go-cty v1.15.0 // indirect
go.opentelemetry.io/otel/metric v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
github.com/zclconf/go-cty v1.15.1 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/tools v0.26.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -1,5 +1,5 @@
ariga.io/atlas v0.28.1 h1:cNE0FYmoYs1u4KF+FGnp2on1srhM6FDpjaCgL7Rd8/c=
ariga.io/atlas v0.28.1/go.mod h1:LOOp18LCL9r+VifvVlJqgYJwYl271rrXD9/wIyzJ8sw=
ariga.io/atlas v0.29.0 h1:sXlI6ktGjo0vpBDvStjtgEKwLvjFfveK0vmRRTxyu1E=
ariga.io/atlas v0.29.0/go.mod h1:LOOp18LCL9r+VifvVlJqgYJwYl271rrXD9/wIyzJ8sw=
entgo.io/contrib v0.6.0 h1:xfo4TbJE7sJZWx7BV7YrpSz7IPFvS8MzL3fnfzZjKvQ=
entgo.io/contrib v0.6.0/go.mod h1:3qWIseJ/9Wx2Hu5zVh15FDzv7d/UvKNcYKdViywWCQg=
entgo.io/ent v0.14.1 h1:fUERL506Pqr92EPHJqr8EYxbPioflJo6PudkrEA8a/s=
@@ -18,8 +18,8 @@ github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
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.8.1 h1:nK+NRp8C+wQk7tr55K9Er7nBjmBLYGbnyNz7UIy37qw=
github.com/go-kratos/kratos/v2 v2.8.1/go.mod h1:+Vfe3FzF0d+BfMdajA11jT0rAyJWublRE/seZQNZVxE=
github.com/go-kratos/kratos/v2 v2.8.2 h1:EsEA7AmPQ2YQQ0FZrDWO2HgBNqeWM8z/mWKzS5UkQaQ=
github.com/go-kratos/kratos/v2 v2.8.2/go.mod h1:+Vfe3FzF0d+BfMdajA11jT0rAyJWublRE/seZQNZVxE=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -35,8 +35,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M=
github.com/hashicorp/hcl/v2 v2.22.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -51,47 +51,49 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/sony/sonyflake v1.2.0 h1:Pfr3A+ejSg+0SPqpoAmQgEtNDAhc2G1SUYk205qVMLQ=
github.com/sony/sonyflake v1.2.0/go.mod h1:LORtCywH/cq10ZbyfhKrHYgAUGH7mOBa76enV9txy/Y=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/zclconf/go-cty v1.15.1 h1:RgQYm4j2EvoBRXOPxhUvxPzRrGDo1eCOhHXuGfrj5S0=
github.com/zclconf/go-cty v1.15.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@@ -3,14 +3,13 @@ package entgo
import (
"encoding/json"
"fmt"
"github.com/tx7do/go-utils/stringcase"
"strings"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/tx7do/go-utils/stringcase"
)
type FilterOp int
@@ -63,16 +62,6 @@ var ops = [...]string{
FilterSearch: "search",
}
func hasOperations(str string) bool {
str = strings.ToLower(str)
for _, item := range ops {
if str == item {
return true
}
}
return false
}
type DatePart int
const (
@@ -109,6 +98,38 @@ var dateParts = [...]string{
DatePartMicrosecond: "microsecond",
}
const (
QueryDelimiter = "__" // 分隔符
JsonFieldDelimiter = "." // JSONB字段分隔符
)
// splitQueryKey 分割查询键
func splitQueryKey(key string) []string {
return strings.Split(key, QueryDelimiter)
}
// splitJsonFieldKey 分割JSON字段键
func splitJsonFieldKey(key string) []string {
return strings.Split(key, JsonFieldDelimiter)
}
// isJsonFieldKey 是否为JSON字段键
func isJsonFieldKey(key string) bool {
return strings.Contains(key, JsonFieldDelimiter)
}
// hasOperations 是否有操作
func hasOperations(str string) bool {
str = strings.ToLower(str)
for _, item := range ops {
if str == item {
return true
}
}
return false
}
// hasDatePart 是否有日期部分
func hasDatePart(str string) bool {
str = strings.ToLower(str)
for _, item := range dateParts {
@@ -119,6 +140,32 @@ func hasDatePart(str string) bool {
return false
}
// BuildFilterSelector 构建过滤选择器
func BuildFilterSelector(andFilterJsonString, orFilterJsonString string) (error, []func(s *sql.Selector)) {
var err error
var queryConditions []func(s *sql.Selector)
var andSelector func(s *sql.Selector)
err, andSelector = QueryCommandToWhereConditions(andFilterJsonString, false)
if err != nil {
return err, nil
}
if andSelector != nil {
queryConditions = append(queryConditions, andSelector)
}
var orSelector func(s *sql.Selector)
err, orSelector = QueryCommandToWhereConditions(orFilterJsonString, true)
if err != nil {
return err, nil
}
if orSelector != nil {
queryConditions = append(queryConditions, orSelector)
}
return nil, queryConditions
}
// QueryCommandToWhereConditions 查询命令转换为选择条件
func QueryCommandToWhereConditions(strJson string, isOr bool) (error, func(s *sql.Selector)) {
if len(strJson) == 0 {
@@ -150,14 +197,13 @@ func QueryCommandToWhereConditions(strJson string, isOr bool) (error, func(s *sq
}
}
// processQueryMap 处理查询映射表
func processQueryMap(s *sql.Selector, queryMap map[string]string) []*sql.Predicate {
var ps []*sql.Predicate
for k, v := range queryMap {
key := stringcase.ToSnakeCase(k)
keys := splitQueryKey(k)
keys := strings.Split(key, "__")
if cond := oneFieldFilter(s, keys, v); cond != nil {
if cond := makeFieldFilter(s, keys, v); cond != nil {
ps = append(ps, cond)
}
}
@@ -165,32 +211,8 @@ func processQueryMap(s *sql.Selector, queryMap map[string]string) []*sql.Predica
return ps
}
func BuildFilterSelector(andFilterJsonString, orFilterJsonString string) (error, []func(s *sql.Selector)) {
var err error
var queryConditions []func(s *sql.Selector)
var andSelector func(s *sql.Selector)
err, andSelector = QueryCommandToWhereConditions(andFilterJsonString, false)
if err != nil {
return err, nil
}
if andSelector != nil {
queryConditions = append(queryConditions, andSelector)
}
var orSelector func(s *sql.Selector)
err, orSelector = QueryCommandToWhereConditions(orFilterJsonString, true)
if err != nil {
return err, nil
}
if orSelector != nil {
queryConditions = append(queryConditions, orSelector)
}
return nil, queryConditions
}
func oneFieldFilter(s *sql.Selector, keys []string, value string) *sql.Predicate {
// makeFieldFilter 构建一个字段过滤器
func makeFieldFilter(s *sql.Selector, keys []string, value string) *sql.Predicate {
if len(keys) == 0 {
return nil
}
@@ -207,6 +229,21 @@ func oneFieldFilter(s *sql.Selector, keys []string, value string) *sql.Predicate
switch len(keys) {
case 1:
if isJsonFieldKey(field) {
jsonFields := splitJsonFieldKey(field)
if len(jsonFields) != 2 {
field = stringcase.ToSnakeCase(field)
return filterEqual(s, p, field, value)
}
value = "'" + value + "'"
return filterJsonb(
s, p,
stringcase.ToSnakeCase(jsonFields[1]),
stringcase.ToSnakeCase(jsonFields[0]),
).
EQ("", value)
}
field = stringcase.ToSnakeCase(field)
return filterEqual(s, p, field, value)
case 2:
@@ -215,6 +252,19 @@ func oneFieldFilter(s *sql.Selector, keys []string, value string) *sql.Predicate
return nil
}
if isJsonFieldKey(field) {
jsonFields := splitJsonFieldKey(field)
if len(jsonFields) == 2 {
field = filterJsonbField(s,
stringcase.ToSnakeCase(jsonFields[1]),
stringcase.ToSnakeCase(jsonFields[0]),
)
value = "'" + value + "'"
}
} else {
field = stringcase.ToSnakeCase(field)
}
var cond *sql.Predicate
if hasOperations(op) {
return processOp(s, p, op, field, value)
@@ -241,10 +291,22 @@ func oneFieldFilter(s *sql.Selector, keys []string, value string) *sql.Predicate
//var cond *sql.Predicate
if hasDatePart(op1) {
if isJsonFieldKey(field) {
jsonFields := splitJsonFieldKey(field)
if len(jsonFields) == 2 {
field = filterJsonbField(s, jsonFields[1], jsonFields[0])
value = "'" + value + "'"
}
} else {
field = stringcase.ToSnakeCase(field)
}
str := filterDatePartField(s, op1, field)
if hasOperations(op2) {
return processOp(s, p, op2, str, value)
}
return nil
} else {
str := filterJsonbField(s, op1, field)
@@ -547,6 +609,7 @@ func filterDatePart(s *sql.Selector, p *sql.Predicate, datePart, field string) *
return p
}
// filterDatePartField 日期
func filterDatePartField(s *sql.Selector, datePart, field string) string {
p := sql.P()
switch s.Builder.Dialect() {
@@ -565,12 +628,14 @@ func filterDatePartField(s *sql.Selector, datePart, field string) string {
}
// filterJsonb 提取JSONB字段
// Postgresql: WHERE ("app_profile"."preferences" -> daily_email) = 'true'
// Postgresql: WHERE ("app_profile"."preferences" ->> 'daily_email') = 'true'
func filterJsonb(s *sql.Selector, p *sql.Predicate, jsonbField, field string) *sql.Predicate {
field = stringcase.ToSnakeCase(field)
p.Append(func(b *sql.Builder) {
switch s.Builder.Dialect() {
case dialect.Postgres:
b.Ident(s.C(field)).WriteString(" -> ").WriteString(jsonbField)
b.Ident(s.C(field)).WriteString(" ->> ").WriteString("'" + jsonbField + "'")
//b.Arg(strings.ToLower(value))
break
@@ -584,11 +649,14 @@ func filterJsonb(s *sql.Selector, p *sql.Predicate, jsonbField, field string) *s
return p
}
// filterJsonbField JSONB字段
func filterJsonbField(s *sql.Selector, jsonbField, field string) string {
field = stringcase.ToSnakeCase(field)
p := sql.P()
switch s.Builder.Dialect() {
case dialect.Postgres:
p.Ident(s.C(field)).WriteString(" -> ").WriteString(jsonbField)
p.Ident(s.C(field)).WriteString(" ->> ").WriteString("'" + jsonbField + "'")
//b.Arg(strings.ToLower(value))
break

View File

@@ -681,14 +681,104 @@ func TestFilter(t *testing.T) {
s.Where(p)
query, args := s.Query()
require.Equal(t, "SELECT * FROM \"app_profile\" WHERE \"app_profile\".\"preferences\" -> daily_email = $1", query)
require.Equal(t, "SELECT * FROM \"app_profile\" WHERE \"app_profile\".\"preferences\" ->> 'daily_email' = $1", query)
require.NotEmpty(t, args)
require.Equal(t, args[0], "true")
})
}
func TestFilterJsonbField(t *testing.T) {
s := sql.Dialect(dialect.Postgres).Select("*").From(sql.Table("app_profile"))
str := filterJsonbField(s, "daily_email", "preferences")
fmt.Println(str)
t.Run("filterJsonbField", func(t *testing.T) {
s := sql.Dialect(dialect.Postgres).Select("*").From(sql.Table("app_profile"))
str := filterJsonbField(s, "daily_email", "preferences")
fmt.Println(str)
require.Equal(t, str, "\"app_profile\".\"preferences\" ->> 'daily_email'")
})
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
t.Run("MySQL_FilterEqual", func(t *testing.T) {
s := sql.Dialect(dialect.MySQL).Select("*").From(sql.Table("menus"))
p := sql.P()
p = makeFieldFilter(s, []string{"meta.title"}, "tom")
s.Where(p)
query, args := s.Query()
require.Equal(t, "SELECT * FROM `menus` WHERE JSON_EXTRACT(`menus`.`meta`, '$.title') = ?", query)
require.NotEmpty(t, args)
require.Equal(t, args[0], "'tom'")
})
t.Run("PostgreSQL_FilterEqual", func(t *testing.T) {
s := sql.Dialect(dialect.Postgres).Select("*").From(sql.Table("menus"))
p := sql.P()
p = makeFieldFilter(s, []string{"meta.title"}, "tom")
s.Where(p)
query, args := s.Query()
require.Equal(t, "SELECT * FROM \"menus\" WHERE \"menus\".\"meta\" ->> 'title' = $1", query)
require.NotEmpty(t, args)
require.Equal(t, args[0], "'tom'")
})
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
t.Run("MySQL_FilterNot", func(t *testing.T) {
s := sql.Dialect(dialect.MySQL).Select("*").From(sql.Table("users"))
p := sql.P()
p = makeFieldFilter(s, []string{"meta.title", "not"}, "tom")
s.Where(p)
query, args := s.Query()
require.Equal(t, "SELECT * FROM `users` WHERE NOT JSON_EXTRACT(`users`.`meta`, '$.title') = ?", query)
require.NotEmpty(t, args)
require.Equal(t, args[0], "'tom'")
})
t.Run("PostgreSQL_FilterNot", func(t *testing.T) {
s := sql.Dialect(dialect.Postgres).Select("*").From(sql.Table("users"))
p := sql.P()
p = makeFieldFilter(s, []string{"meta.title", "not"}, "tom")
s.Where(p)
query, args := s.Query()
require.Equal(t, "SELECT * FROM \"users\" WHERE NOT \"users\".\"meta\" ->> 'title' = $1", query)
require.NotEmpty(t, args)
require.Equal(t, args[0], "'tom'")
})
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
t.Run("MySQL_FilterNot_Date", func(t *testing.T) {
s := sql.Dialect(dialect.MySQL).Select("*").From(sql.Table("users"))
p := sql.P()
p = makeFieldFilter(s, []string{"meta.title", "date", "not"}, "2023-01-01")
s.Where(p)
query, args := s.Query()
require.Equal(t, "SELECT * FROM `users` WHERE NOT DATE(JSON_EXTRACT(`users`.`meta`, '$.title')) = ?", query)
require.NotEmpty(t, args)
require.Equal(t, args[0], "'2023-01-01'")
})
t.Run("PostgreSQL_FilterNot_Date", func(t *testing.T) {
s := sql.Dialect(dialect.Postgres).Select("*").From(sql.Table("users"))
p := sql.P()
p = makeFieldFilter(s, []string{"meta.title", "date", "not"}, "2023-01-01")
s.Where(p)
query, args := s.Query()
require.Equal(t, "SELECT * FROM \"users\" WHERE NOT EXTRACT('DATE' FROM \"users\".\"meta\" ->> 'title') = $1", query)
require.NotEmpty(t, args)
require.Equal(t, args[0], "'2023-01-01'")
})
}

View File

@@ -3,7 +3,6 @@ package entgo
import (
"encoding/json"
"fmt"
"strings"
"testing"
"entgo.io/ent/dialect"
@@ -85,11 +84,11 @@ func TestJsonCodec(t *testing.T) {
func TestSplitQuery(t *testing.T) {
var keys []string
keys = strings.Split("id", "__")
keys = splitQueryKey("id")
assert.Equal(t, len(keys), 1)
assert.Equal(t, keys[0], "id")
keys = strings.Split("id__not", "__")
keys = splitQueryKey("id__not")
assert.Equal(t, len(keys), 2)
assert.Equal(t, keys[0], "id")
assert.Equal(t, keys[1], "not")
@@ -111,19 +110,22 @@ func TestBuildQuerySelectorDefault(t *testing.T) {
{"PostgreSQL_NoPagination", dialect.Postgres, "", "", true, "SELECT * FROM \"users\" ORDER BY \"users\".\"created_at\" DESC"},
{"MySQL_JsonbQuery", dialect.MySQL, "{\"preferences__daily_email\" : \"true\"}", "", true, "SELECT * FROM `users` WHERE JSON_EXTRACT(`users`.`preferences`, '$.daily_email') = ? ORDER BY `users`.`created_at` DESC"},
{"PostgreSQL_JsonbQuery", dialect.Postgres, "{\"preferences__daily_email\" : \"true\"}", "", true, "SELECT * FROM \"users\" WHERE \"users\".\"preferences\" -> daily_email = $1 ORDER BY \"users\".\"created_at\" DESC"},
{"PostgreSQL_JsonbQuery", dialect.Postgres, "{\"preferences__daily_email\" : \"true\"}", "", true, "SELECT * FROM \"users\" WHERE \"users\".\"preferences\" ->> 'daily_email' = $1 ORDER BY \"users\".\"created_at\" DESC"},
{"MySQL_DatePartQuery", dialect.MySQL, "{\"created_at__date\" : \"2023-01-01\"}", "", true, "SELECT * FROM `users` WHERE DATE(`users`.`created_at`) = ? ORDER BY `users`.`created_at` DESC"},
{"PostgreSQL_DatePartQuery", dialect.Postgres, "{\"created_at__date\" : \"2023-01-01\"}", "", true, "SELECT * FROM \"users\" WHERE EXTRACT('DATE' FROM \"users\".\"created_at\") = $1 ORDER BY \"users\".\"created_at\" DESC"},
{"MySQL_JsonbCombineQuery", dialect.MySQL, "{\"preferences__pub_date__not\" : \"true\"}", "", true, "SELECT * FROM `users` WHERE NOT JSON_EXTRACT(`users`.`preferences`, '$.pub_date') = ? ORDER BY `users`.`created_at` DESC"},
{"PostgreSQL_JsonbCombineQuery", dialect.Postgres, "{\"preferences__pub_date__not\" : \"true\"}", "", true, "SELECT * FROM \"users\" WHERE NOT \"users\".\"preferences\" -> pub_date = $1 ORDER BY \"users\".\"created_at\" DESC"},
{"PostgreSQL_JsonbCombineQuery", dialect.Postgres, "{\"preferences__pub_date__not\" : \"true\"}", "", true, "SELECT * FROM \"users\" WHERE NOT \"users\".\"preferences\" ->> 'pub_date' = $1 ORDER BY \"users\".\"created_at\" DESC"},
{"MySQL_DatePartCombineQuery", dialect.MySQL, "{\"pub_date__date__not\" : \"true\"}", "", true, "SELECT * FROM `users` WHERE NOT DATE(`users`.`pub_date`) = ? ORDER BY `users`.`created_at` DESC"},
{"PostgreSQL_DatePartCombineQuery", dialect.Postgres, "{\"pub_date__date__not\" : \"true\"}", "", true, "SELECT * FROM \"users\" WHERE NOT EXTRACT('DATE' FROM \"users\".\"pub_date\") = $1 ORDER BY \"users\".\"created_at\" DESC"},
{"MySQL_DatePartRangeQuery", dialect.MySQL, "{\"pub_date__date__range\" : \"[\\\"2023-10-25\\\", \\\"2024-10-25\\\"]\"}", "", true, "SELECT * FROM `users` WHERE DATE(`users`.`pub_date`) >= ? AND DATE(`users`.`pub_date`) <= ? ORDER BY `users`.`created_at` DESC"},
{"PostgreSQL_DatePartRangeQuery", dialect.Postgres, "{\"pub_date__date__range\" : \"[\\\"2023-10-25\\\", \\\"2024-10-25\\\"]\"}", "", true, "SELECT * FROM \"users\" WHERE EXTRACT('DATE' FROM \"users\".\"pub_date\") >= $1 AND EXTRACT('DATE' FROM \"users\".\"pub_date\") <= $2 ORDER BY \"users\".\"created_at\" DESC"},
{"MySQL_JsonQuery", dialect.MySQL, "{\"meta.title\" : \"preferences__daily_email\"}", "", true, "SELECT * FROM `users` WHERE JSON_EXTRACT(`users`.`meta`, '$.title') = ? ORDER BY `users`.`created_at` DESC"},
{"PostgreSQL_JsonQuery", dialect.Postgres, "{\"meta.title\" : \"preferences__daily_email\"}", "", true, "SELECT * FROM \"users\" WHERE \"users\".\"meta\" ->> 'title' = $1 ORDER BY \"users\".\"created_at\" DESC"},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {

View File

@@ -1,8 +1,16 @@
package entgo
import (
"fmt"
"strings"
"entgo.io/ent/dialect/sql"
"github.com/tx7do/go-utils/fieldmaskutil"
"github.com/tx7do/go-utils/stringcase"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)
func BuildSetNullUpdate(u *sql.UpdateBuilder, fields []string) {
@@ -14,12 +22,79 @@ func BuildSetNullUpdate(u *sql.UpdateBuilder, fields []string) {
}
}
func BuildSetNullUpdater(fields []string) (error, func(u *sql.UpdateBuilder)) {
if len(fields) > 0 {
return nil, func(u *sql.UpdateBuilder) {
BuildSetNullUpdate(u, fields)
}
} else {
return nil, nil
// BuildSetNullUpdater 构建一个UpdateBuilder,用于清空字段的值
func BuildSetNullUpdater(fields []string) func(u *sql.UpdateBuilder) {
if len(fields) == 0 {
return nil
}
return func(u *sql.UpdateBuilder) {
BuildSetNullUpdate(u, fields)
}
}
// ExtractJsonFieldKeyValues 提取json字段的键值对
func ExtractJsonFieldKeyValues(msg proto.Message, paths []string, needToSnakeCase bool) []string {
var keyValues []string
rft := msg.ProtoReflect()
for _, path := range paths {
fd := rft.Descriptor().Fields().ByName(protoreflect.Name(path))
if fd == nil {
continue
}
if !rft.Has(fd) {
continue
}
var k string
if needToSnakeCase {
k = stringcase.ToSnakeCase(path)
} else {
k = path
}
keyValues = append(keyValues, fmt.Sprintf("'%s'", k))
v := rft.Get(fd)
switch v.Interface().(type) {
case int32, int64, uint32, uint64, float32, float64, bool:
keyValues = append(keyValues, fmt.Sprintf("%d", v.Interface()))
case string:
keyValues = append(keyValues, fmt.Sprintf("'%s'", v.Interface()))
}
}
return keyValues
}
// SetJsonNullFieldUpdateBuilder 设置json字段的空值
func SetJsonNullFieldUpdateBuilder(fieldName string, msg proto.Message, paths []string) func(u *sql.UpdateBuilder) {
nilPaths := fieldmaskutil.NilValuePaths(msg, paths)
if len(nilPaths) == 0 {
return nil
}
return func(u *sql.UpdateBuilder) {
u.Set(fieldName,
sql.Expr(
fmt.Sprintf("\"%s\" - '{%s}'::text[]", fieldName, strings.Join(nilPaths, ",")),
),
)
}
}
// SetJsonFieldValueUpdateBuilder 设置json字段的值
func SetJsonFieldValueUpdateBuilder(fieldName string, msg proto.Message, paths []string, needToSnakeCase bool) func(u *sql.UpdateBuilder) {
keyValues := ExtractJsonFieldKeyValues(msg, paths, needToSnakeCase)
if len(keyValues) == 0 {
return nil
}
return func(u *sql.UpdateBuilder) {
u.Set(fieldName,
sql.Expr(
fmt.Sprintf("\"%s\" || jsonb_build_object(%s)", fieldName, strings.Join(keyValues, ",")),
),
)
}
}

View File

@@ -5,10 +5,10 @@ go 1.21
toolchain go1.23.2
require (
github.com/go-kratos/kratos/v2 v2.8.1
github.com/go-kratos/kratos/v2 v2.8.2
github.com/oschwald/geoip2-golang v1.11.0
github.com/stretchr/testify v1.9.0
golang.org/x/text v0.19.0
golang.org/x/text v0.20.0
)
require (
@@ -16,7 +16,7 @@ require (
github.com/kr/text v0.2.0 // indirect
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/sys v0.27.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -1,8 +1,8 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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.8.1 h1:nK+NRp8C+wQk7tr55K9Er7nBjmBLYGbnyNz7UIy37qw=
github.com/go-kratos/kratos/v2 v2.8.1/go.mod h1:+Vfe3FzF0d+BfMdajA11jT0rAyJWublRE/seZQNZVxE=
github.com/go-kratos/kratos/v2 v2.8.2 h1:EsEA7AmPQ2YQQ0FZrDWO2HgBNqeWM8z/mWKzS5UkQaQ=
github.com/go-kratos/kratos/v2 v2.8.2/go.mod h1:+Vfe3FzF0d+BfMdajA11jT0rAyJWublRE/seZQNZVxE=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -17,12 +17,12 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

4
go.mod
View File

@@ -10,8 +10,8 @@ require (
github.com/gosimple/slug v1.14.0
github.com/sony/sonyflake v1.2.0
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.28.0
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
golang.org/x/crypto v0.29.0
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
google.golang.org/protobuf v1.35.1
)

8
go.sum
View File

@@ -28,10 +28,10 @@ github.com/sony/sonyflake v1.2.0 h1:Pfr3A+ejSg+0SPqpoAmQgEtNDAhc2G1SUYk205qVMLQ=
github.com/sony/sonyflake v1.2.0/go.mod h1:LORtCywH/cq10ZbyfhKrHYgAUGH7mOBa76enV9txy/Y=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

10
tag.bat
View File

@@ -1,9 +1,9 @@
git tag v1.1.12
git tag v1.1.13
git tag bank_card/v1.1.2
git tag geoip/v1.1.2
git tag bank_card/v1.1.3
git tag geoip/v1.1.3
git tag entgo/v1.1.15
git tag gorm/v1.1.2
git tag entgo/v1.1.23
git tag gorm/v1.1.3
git push origin --tags

View File

@@ -1,4 +1,4 @@
package util
package timeutil
import "time"

View File

@@ -1,4 +1,4 @@
package util
package timeutil
import (
"math"

View File

@@ -1,4 +1,4 @@
package util
package timeutil
import (
"testing"

View File

@@ -1,4 +1,4 @@
package util
package timeutil
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package util
package timeutil
import "time"

View File

@@ -1,4 +1,4 @@
package util
package timeutil
import (
"fmt"

View File

@@ -1,8 +1,9 @@
package util
package timeutil
import (
"time"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/tx7do/go-utils/trans"
@@ -132,3 +133,19 @@ func TimeToTimestamppb(tm *time.Time) *timestamppb.Timestamp {
}
return nil
}
func FloatToDurationpb(duration *float64, timePrecision time.Duration) *durationpb.Duration {
if duration == nil {
return nil
}
return durationpb.New(time.Duration(*duration) * timePrecision)
}
func DurationpbToFloat(duration *durationpb.Duration, timePrecision time.Duration) *float64 {
if duration == nil {
return nil
}
seconds := duration.AsDuration().Seconds()
secondsWithPrecision := seconds / timePrecision.Seconds()
return &secondsWithPrecision
}

View File

@@ -1,4 +1,4 @@
package util
package timeutil
import (
"fmt"