Compare commits

..

5 Commits

Author SHA1 Message Date
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
12 changed files with 123 additions and 54 deletions

View File

@@ -63,16 +63,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 +99,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 +141,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 +198,15 @@ 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 := strings.Split(key, "__")
keys := splitQueryKey(key)
if cond := oneFieldFilter(s, keys, v); cond != nil {
if cond := makeFieldFilter(s, keys, v); cond != nil {
ps = append(ps, cond)
}
}
@@ -165,32 +214,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 +232,13 @@ 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 {
return filterEqual(s, p, field, value)
}
return filterJsonb(s, p, jsonFields[0], jsonFields[1]).EQ("", value)
}
return filterEqual(s, p, field, value)
case 2:
@@ -215,6 +247,14 @@ 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, op, field)
value = "'" + value + "'"
}
}
var cond *sql.Predicate
if hasOperations(op) {
return processOp(s, p, op, field, value)
@@ -241,10 +281,19 @@ 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, op2, field)
value = "'" + value + "'"
}
}
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 +596,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 +615,12 @@ 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 {
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 +634,12 @@ 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 {
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

@@ -7,6 +7,7 @@ import (
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -681,7 +682,7 @@ 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")
})
@@ -691,4 +692,5 @@ 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)
assert.Equal(t, str, "\"app_profile\".\"preferences\" ->> 'daily_email'")
}

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")

View File

@@ -3,7 +3,7 @@ git tag v1.1.13
git tag bank_card/v1.1.3
git tag geoip/v1.1.3
git tag entgo/v1.1.18
git tag entgo/v1.1.21
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"