From d53ddf780f5c04db7118f4afda0da4b44f3c5632 Mon Sep 17 00:00:00 2001 From: liangminhua Date: Sun, 1 Jun 2025 01:59:59 +0800 Subject: [PATCH] schema/field: add rune length validators for string fields Signed-off-by: liangminhua --- schema/field/field.go | 26 +++++++++++++++++++++++++ schema/field/field_test.go | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/schema/field/field.go b/schema/field/field.go index 07ce080953..541faf141f 100644 --- a/schema/field/field.go +++ b/schema/field/field.go @@ -15,6 +15,7 @@ import ( "regexp" "strings" "time" + "unicode/utf8" "entgo.io/ent/schema" ) @@ -222,6 +223,18 @@ func (b *stringBuilder) MinLen(i int) *stringBuilder { return b } +// MinRuneLen adds a rune length validator for this field. +// Operation fails if the rune count of the string is less than the given value. +func (b *stringBuilder) MinRuneLen(i int) *stringBuilder { + b.desc.Validators = append(b.desc.Validators, func(v string) error { + if utf8.RuneCountInString(v) < i { + return errors.New("value is less than the required rune length") + } + return nil + }) + return b +} + // NotEmpty adds a length validator for this field. // Operation fails if the length of the string is zero. func (b *stringBuilder) NotEmpty() *stringBuilder { @@ -241,6 +254,19 @@ func (b *stringBuilder) MaxLen(i int) *stringBuilder { return b } +// MaxRuneLen adds a rune length validator for this field. +// Operation fails if the rune count of the string is greater than the given value. +func (b *stringBuilder) MaxRuneLen(i int) *stringBuilder { + b.desc.Size = i + b.desc.Validators = append(b.desc.Validators, func(v string) error { + if utf8.RuneCountInString(v) > i { + return errors.New("value is greater than the required rune length") + } + return nil + }) + return b +} + // Validate adds a validator for this field. Operation fails if the validation fails. func (b *stringBuilder) Validate(fn func(string) error) *stringBuilder { b.desc.Validators = append(b.desc.Validators, fn) diff --git a/schema/field/field_test.go b/schema/field/field_test.go index aed0f7256e..472a894f7d 100644 --- a/schema/field/field_test.go +++ b/schema/field/field_test.go @@ -975,3 +975,43 @@ func TestTypeConstName(t *testing.T) { typ = 21 assert.Equal(t, "invalid", typ.ConstName()) } + +func TestString_MinRuneLen(t *testing.T) { + fd := field.String("name").MinRuneLen(5).Descriptor() + assert.Len(t, fd.Validators, 1) + + err := fd.Validators[0].(func(string) error)("hello") + assert.NoError(t, err) + + err = fd.Validators[0].(func(string) error)("hi") + assert.EqualError(t, err, "value is less than the required rune length") + + err = fd.Validators[0].(func(string) error)("你好") + assert.EqualError(t, err, "value is less than the required rune length") + + err = fd.Validators[0].(func(string) error)("你好世界!") + assert.NoError(t, err) + + err = fd.Validators[0].(func(string) error)("") + assert.Error(t, err) +} + +func TestString_MaxRuneLen(t *testing.T) { + fd := field.String("name").MaxRuneLen(5).Descriptor() + assert.Len(t, fd.Validators, 1) + + err := fd.Validators[0].(func(string) error)("hello") + assert.NoError(t, err) + + err = fd.Validators[0].(func(string) error)("hello world") + assert.EqualError(t, err, "value is greater than the required rune length") + + err = fd.Validators[0].(func(string) error)("你好世界你好") + assert.EqualError(t, err, "value is greater than the required rune length") + + err = fd.Validators[0].(func(string) error)("你好世界!") + assert.NoError(t, err) + + err = fd.Validators[0].(func(string) error)("") + assert.NoError(t, err) +}