Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring #58

Merged
merged 1 commit into from
Oct 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4151,15 +4151,15 @@ Valix provides a rich set of pre-defined common constraints - listed here for re
<table>
<tr>
<td>
<code>AllowRanges</code> <em>[]*unicode.RangeTable</em>
<code>AllowRanges</code> <em>[]unicode.RangeTable</em>
</td>
<td>
the ranges of characters (runes) that are allowed - each character must be in at least one of these
</td>
</tr>
<tr>
<td>
<code>DisallowRanges</code> <em>[]*unicode.RangeTable</em>
<code>DisallowRanges</code> <em>[]unicode.RangeTable</em>
</td>
<td>
the ranges of characters (runes) that are not allowed - if any character is in any of these ranges then the constraint is violated
Expand Down Expand Up @@ -6366,10 +6366,10 @@ var MySet = &valix.ConstraintSet{
return true, ""
}, ""),
&valix.StringCharacters{
AllowRanges: []*unicode.RangeTable{
AllowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{'0', 'z', 1}}},
},
DisallowRanges: []*unicode.RangeTable{
DisallowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{0x003a, 0x0040, 1}}},
{R16: []unicode.Range16{{0x005b, 0x005e, 1}}},
{R16: []unicode.Range16{{0x0060, 0x0060, 1}}},
Expand Down
116 changes: 66 additions & 50 deletions constraint_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,56 +239,56 @@ func defaultConstraints() map[string]Constraint {
"iso4217-numeric": &StringValidCurrencyCode{NumericOnly: true},
"lang": &StringValidLanguageCode{},
// preset patterns...
presetTokenAlpha: &StringPresetPattern{Preset: presetTokenAlpha},
presetTokenAlphaNumeric: &StringPresetPattern{Preset: presetTokenAlphaNumeric},
presetTokenBarcode: &StringPresetPattern{Preset: presetTokenBarcode},
presetTokenBase64: &StringPresetPattern{Preset: presetTokenBase64},
presetTokenBase64URL: &StringPresetPattern{Preset: presetTokenBase64URL},
presetTokenCard: &StringPresetPattern{Preset: presetTokenCard},
presetTokenCMYK: &StringPresetPattern{Preset: presetTokenCMYK},
presetTokenCMYK300: &StringPresetPattern{Preset: presetTokenCMYK300},
presetTokenE164: &StringPresetPattern{Preset: presetTokenE164},
presetTokenEAN: &StringPresetPattern{Preset: presetTokenEAN},
presetTokenEAN8: &StringPresetPattern{Preset: presetTokenEAN8},
presetTokenEAN13: &StringPresetPattern{Preset: presetTokenEAN13},
presetTokenDUN14: &StringPresetPattern{Preset: presetTokenDUN14},
presetTokenEAN14: &StringPresetPattern{Preset: presetTokenEAN14},
presetTokenEAN18: &StringPresetPattern{Preset: presetTokenEAN18},
presetTokenEAN99: &StringPresetPattern{Preset: presetTokenEAN99},
presetTokenHexadecimal: &StringPresetPattern{Preset: presetTokenHexadecimal},
presetTokenHsl: &StringPresetPattern{Preset: presetTokenHsl},
presetTokenHsla: &StringPresetPattern{Preset: presetTokenHsla},
presetTokenHtmlColor: &StringPresetPattern{Preset: presetTokenHtmlColor},
presetTokenInteger: &StringPresetPattern{Preset: presetTokenInteger},
presetTokenISBN: &StringPresetPattern{Preset: presetTokenISBN},
presetTokenISBN10: &StringPresetPattern{Preset: presetTokenISBN10},
presetTokenISBN13: &StringPresetPattern{Preset: presetTokenISBN13},
presetTokenISSN: &StringPresetPattern{Preset: presetTokenISSN},
presetTokenISSN8: &StringPresetPattern{Preset: presetTokenISSN8},
presetTokenISSN13: &StringPresetPattern{Preset: presetTokenISSN13},
presetTokenNumeric: &StringPresetPattern{Preset: presetTokenNumeric},
presetTokenNumericE: &StringPresetPattern{Preset: presetTokenNumericE},
presetTokenNumericX: &StringPresetPattern{Preset: presetTokenNumericX},
presetTokenPublication: &StringPresetPattern{Preset: presetTokenPublication},
presetTokenRgb: &StringPresetPattern{Preset: presetTokenRgb},
presetTokenRgba: &StringPresetPattern{Preset: presetTokenRgba},
presetTokenRgbIcc: &StringPresetPattern{Preset: presetTokenRgbIcc},
presetTokenULID: &StringPresetPattern{Preset: presetTokenULID},
presetTokenUPC: &StringPresetPattern{Preset: presetTokenUPC},
presetTokenUPCA: &StringPresetPattern{Preset: presetTokenUPCA},
presetTokenUPCE: &StringPresetPattern{Preset: presetTokenUPCE},
presetTokenUuid: &StringPresetPattern{Preset: presetTokenUuid},
presetTokenUUID: &StringPresetPattern{Preset: presetTokenUUID},
presetTokenUuid1: &StringPresetPattern{Preset: presetTokenUuid1},
presetTokenUUID1: &StringPresetPattern{Preset: presetTokenUUID1},
presetTokenUuid2: &StringPresetPattern{Preset: presetTokenUuid2},
presetTokenUUID2: &StringPresetPattern{Preset: presetTokenUUID2},
presetTokenUuid3: &StringPresetPattern{Preset: presetTokenUuid3},
presetTokenUUID3: &StringPresetPattern{Preset: presetTokenUUID3},
presetTokenUuid4: &StringPresetPattern{Preset: presetTokenUuid4},
presetTokenUUID4: &StringPresetPattern{Preset: presetTokenUUID4},
presetTokenUuid5: &StringPresetPattern{Preset: presetTokenUuid5},
presetTokenUUID5: &StringPresetPattern{Preset: presetTokenUUID5},
PresetAlpha: &StringPresetPattern{Preset: PresetAlpha},
PresetAlphaNumeric: &StringPresetPattern{Preset: PresetAlphaNumeric},
PresetBarcode: &StringPresetPattern{Preset: PresetBarcode},
PresetBase64: &StringPresetPattern{Preset: PresetBase64},
PresetBase64URL: &StringPresetPattern{Preset: PresetBase64URL},
PresetCard: &StringPresetPattern{Preset: PresetCard},
PresetCMYK: &StringPresetPattern{Preset: PresetCMYK},
PresetCMYK300: &StringPresetPattern{Preset: PresetCMYK300},
PresetE164: &StringPresetPattern{Preset: PresetE164},
PresetEAN: &StringPresetPattern{Preset: PresetEAN},
PresetEAN8: &StringPresetPattern{Preset: PresetEAN8},
PresetEAN13: &StringPresetPattern{Preset: PresetEAN13},
PresetDUN14: &StringPresetPattern{Preset: PresetDUN14},
PresetEAN14: &StringPresetPattern{Preset: PresetEAN14},
PresetEAN18: &StringPresetPattern{Preset: PresetEAN18},
PresetEAN99: &StringPresetPattern{Preset: PresetEAN99},
PresetHexadecimal: &StringPresetPattern{Preset: PresetHexadecimal},
PresetHsl: &StringPresetPattern{Preset: PresetHsl},
PresetHsla: &StringPresetPattern{Preset: PresetHsla},
PresetHtmlColor: &StringPresetPattern{Preset: PresetHtmlColor},
PresetInteger: &StringPresetPattern{Preset: PresetInteger},
PresetISBN: &StringPresetPattern{Preset: PresetISBN},
PresetISBN10: &StringPresetPattern{Preset: PresetISBN10},
PresetISBN13: &StringPresetPattern{Preset: PresetISBN13},
PresetISSN: &StringPresetPattern{Preset: PresetISSN},
PresetISSN8: &StringPresetPattern{Preset: PresetISSN8},
PresetISSN13: &StringPresetPattern{Preset: PresetISSN13},
PresetNumeric: &StringPresetPattern{Preset: PresetNumeric},
PresetNumericE: &StringPresetPattern{Preset: PresetNumericE},
PresetNumericX: &StringPresetPattern{Preset: PresetNumericX},
PresetPublication: &StringPresetPattern{Preset: PresetPublication},
PresetRgb: &StringPresetPattern{Preset: PresetRgb},
PresetRgba: &StringPresetPattern{Preset: PresetRgba},
PresetRgbIcc: &StringPresetPattern{Preset: PresetRgbIcc},
PresetULID: &StringPresetPattern{Preset: PresetULID},
PresetUPC: &StringPresetPattern{Preset: PresetUPC},
PresetUPCA: &StringPresetPattern{Preset: PresetUPCA},
PresetUPCE: &StringPresetPattern{Preset: PresetUPCE},
PresetUuid: &StringPresetPattern{Preset: PresetUuid},
PresetUUID: &StringPresetPattern{Preset: PresetUUID},
PresetUuid1: &StringPresetPattern{Preset: PresetUuid1},
PresetUUID1: &StringPresetPattern{Preset: PresetUUID1},
PresetUuid2: &StringPresetPattern{Preset: PresetUuid2},
PresetUUID2: &StringPresetPattern{Preset: PresetUUID2},
PresetUuid3: &StringPresetPattern{Preset: PresetUuid3},
PresetUUID3: &StringPresetPattern{Preset: PresetUUID3},
PresetUuid4: &StringPresetPattern{Preset: PresetUuid4},
PresetUUID4: &StringPresetPattern{Preset: PresetUUID4},
PresetUuid5: &StringPresetPattern{Preset: PresetUuid5},
PresetUUID5: &StringPresetPattern{Preset: PresetUUID5},
}
}

Expand Down Expand Up @@ -341,6 +341,22 @@ func (r *constraintRegistry) get(name string) (Constraint, bool) {
return c, ok
}

// this method is potentially slow - but is only used by PropertyValidator.ToV8nTagString
// Note: finds only the first with matching name!
func (r *constraintRegistry) search(name string) (alias string, constraint Constraint, found bool) {
defer r.sync.Unlock()
r.sync.Lock()
for a, c := range r.namedConstraints {
if name == reflect.TypeOf(c).Elem().Name() {
alias = a
constraint = c
found = true
break
}
}
return
}

// reset for testing
func (r *constraintRegistry) reset() {
defer r.sync.Unlock()
Expand Down
12 changes: 6 additions & 6 deletions constraint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ func TestConstraintSet(t *testing.T) {
return true, ""
}, ""),
&StringCharacters{
AllowRanges: []*unicode.RangeTable{
AllowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{'0', 'z', 1}}},
},
DisallowRanges: []*unicode.RangeTable{
DisallowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{0x003a, 0x0040, 1}}},
{R16: []unicode.Range16{{0x005b, 0x005e, 1}}},
{R16: []unicode.Range16{{0x0060, 0x0060, 1}}},
Expand Down Expand Up @@ -144,10 +144,10 @@ func TestConstraintSetNoMsg(t *testing.T) {
return true, ""
}, "Must start with a capital"),
&StringCharacters{
AllowRanges: []*unicode.RangeTable{
AllowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{'0', 'z', 1}}},
},
DisallowRanges: []*unicode.RangeTable{
DisallowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{0x003a, 0x0040, 1}}},
{R16: []unicode.Range16{{0x005b, 0x005e, 1}}},
{R16: []unicode.Range16{{0x0060, 0x0060, 1}}},
Expand Down Expand Up @@ -211,10 +211,10 @@ func TestConstraintSetCeases(t *testing.T) {
return true, ""
}, "Must start with a capital"),
&StringCharacters{
AllowRanges: []*unicode.RangeTable{
AllowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{'0', 'z', 1}}},
},
DisallowRanges: []*unicode.RangeTable{
DisallowRanges: []unicode.RangeTable{
{R16: []unicode.Range16{{0x003a, 0x0040, 1}}},
{R16: []unicode.Range16{{0x005b, 0x005e, 1}}},
{R16: []unicode.Range16{{0x0060, 0x0060, 1}}},
Expand Down
76 changes: 58 additions & 18 deletions constraint_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,34 +184,31 @@ func truncateTime(t time.Time, truncTime bool) time.Time {
return t
}

var _Bmp = &unicode.RangeTable{
R16: []unicode.Range16{
{0x0000, 0xffff, 1},
},
}
var _Smp = &unicode.RangeTable{
R32: []unicode.Range32{
{0x10000, 0x1ffff, 1},
},
}
var _Sip = &unicode.RangeTable{
R32: []unicode.Range32{
{0x20000, 0x2ffff, 1},
},
}
var (
// UnicodeBMP is a unicode.RangeTable that represents the Unicode BMP (Basic Multilingual Plane)
//
// For use with StringCharacters constraint
UnicodeBMP = _Bmp
UnicodeBMP = unicode.RangeTable{
R16: []unicode.Range16{
{0x0000, 0xffff, 1},
},
}
// UnicodeSMP is a unicode.RangeTable that represents the Unicode SMP (Supplementary Multilingual Plane)
//
// For use with StringCharacters constraint
UnicodeSMP = _Smp
UnicodeSMP = unicode.RangeTable{
R32: []unicode.Range32{
{0x10000, 0x1ffff, 1},
},
}
// UnicodeSIP is a unicode.RangeTable that represents the Unicode SIP (Supplementary Ideographic Plane)
//
// For use with StringCharacters constraint
UnicodeSIP = _Sip
UnicodeSIP = unicode.RangeTable{
R32: []unicode.Range32{
{0x20000, 0x2ffff, 1},
},
}
)

var (
Expand Down Expand Up @@ -585,3 +582,46 @@ func parseDurationNumber(str string) (fv *float64, result bool) {
}
return
}

type stringConstraint interface {
Constraint
checkString(str string, vcx *ValidatorContext) bool
}

func checkStringConstraint(v interface{}, vcx *ValidatorContext, c stringConstraint, strict bool, stop bool) (bool, string) {
if str, ok := v.(string); ok {
if !c.checkString(str, vcx) {
vcx.CeaseFurtherIf(stop)
return false, c.GetMessage(vcx)
}
} else if strict {
vcx.CeaseFurtherIf(stop)
return false, c.GetMessage(vcx)
}
return true, ""
}

type dateCompareConstraint interface {
Constraint
compareDates(value time.Time, other time.Time) bool
}

func checkDateCompareConstraint(value string, other interface{}, vcx *ValidatorContext, c dateCompareConstraint, excTime bool, stop bool) (bool, string) {
if cdt, ok := stringToDatetime(value, excTime); ok {
if dt, ok := isTime(other, excTime); ok && c.compareDates(*cdt, dt) {
return true, ""
}
}
vcx.CeaseFurtherIf(stop)
return false, c.GetMessage(vcx)
}

func checkDateCompareOtherPropertyConstraint(v interface{}, otherPtyName string, vcx *ValidatorContext, c dateCompareConstraint, excTime bool, stop bool) (bool, string) {
if other, ok := getOtherPropertyDatetime(otherPtyName, vcx, excTime, false); ok {
if dt, ok := isTime(v, excTime); ok && c.compareDates(dt, *other) {
return true, ""
}
}
vcx.CeaseFurtherIf(stop)
return false, c.GetMessage(vcx)
}
4 changes: 2 additions & 2 deletions constraint_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,15 +378,15 @@ func TestCoerceJsonNumberToFloat(t *testing.T) {
}

func TestIsUniqueCompare(t *testing.T) {
distinctList := []interface{}{}
distinctList := make([]interface{}, 0)
unique := isUniqueCompare("foo", true, &distinctList)
require.True(t, unique)
unique = isUniqueCompare("Foo", true, &distinctList)
require.False(t, unique)
unique = isUniqueCompare("Foo", false, &distinctList)
require.True(t, unique)

distinctList = []interface{}{}
distinctList = make([]interface{}, 0)
unique = isUniqueCompare(1.0, false, &distinctList)
require.True(t, unique)
unique = isUniqueCompare(json.Number("1"), false, &distinctList)
Expand Down
Loading