filter enhancements
This commit is contained in:
@@ -15,22 +15,36 @@ import (
|
||||
|
||||
var schemaFieldNameRegex = regexp.MustCompile(`^\w+$`)
|
||||
|
||||
// field value modifiers
|
||||
const (
|
||||
FieldValueModifierAdd string = "+"
|
||||
FieldValueModifierSubtract string = "-"
|
||||
)
|
||||
|
||||
// FieldValueModifiers returns a list with all available field modifier tokens.
|
||||
func FieldValueModifiers() []string {
|
||||
return []string{
|
||||
FieldValueModifierAdd,
|
||||
FieldValueModifierSubtract,
|
||||
}
|
||||
}
|
||||
|
||||
// commonly used field names
|
||||
const (
|
||||
FieldNameId = "id"
|
||||
FieldNameCreated = "created"
|
||||
FieldNameUpdated = "updated"
|
||||
FieldNameCollectionId = "collectionId"
|
||||
FieldNameCollectionName = "collectionName"
|
||||
FieldNameExpand = "expand"
|
||||
FieldNameUsername = "username"
|
||||
FieldNameEmail = "email"
|
||||
FieldNameEmailVisibility = "emailVisibility"
|
||||
FieldNameVerified = "verified"
|
||||
FieldNameTokenKey = "tokenKey"
|
||||
FieldNamePasswordHash = "passwordHash"
|
||||
FieldNameLastResetSentAt = "lastResetSentAt"
|
||||
FieldNameLastVerificationSentAt = "lastVerificationSentAt"
|
||||
FieldNameId string = "id"
|
||||
FieldNameCreated string = "created"
|
||||
FieldNameUpdated string = "updated"
|
||||
FieldNameCollectionId string = "collectionId"
|
||||
FieldNameCollectionName string = "collectionName"
|
||||
FieldNameExpand string = "expand"
|
||||
FieldNameUsername string = "username"
|
||||
FieldNameEmail string = "email"
|
||||
FieldNameEmailVisibility string = "emailVisibility"
|
||||
FieldNameVerified string = "verified"
|
||||
FieldNameTokenKey string = "tokenKey"
|
||||
FieldNamePasswordHash string = "passwordHash"
|
||||
FieldNameLastResetSentAt string = "lastResetSentAt"
|
||||
FieldNameLastVerificationSentAt string = "lastVerificationSentAt"
|
||||
)
|
||||
|
||||
// BaseModelFieldNames returns the field names that all models have (id, created, updated).
|
||||
@@ -168,8 +182,8 @@ func (f SchemaField) Validate() error {
|
||||
f.InitOptions()
|
||||
|
||||
excludeNames := BaseModelFieldNames()
|
||||
// exclude filter literals
|
||||
excludeNames = append(excludeNames, "null", "true", "false")
|
||||
// exclude special filter literals
|
||||
excludeNames = append(excludeNames, "null", "true", "false", "isset")
|
||||
// exclude system literals
|
||||
excludeNames = append(excludeNames, SystemFieldNames()...)
|
||||
|
||||
@@ -276,7 +290,7 @@ func (f *SchemaField) PrepareValue(value any) any {
|
||||
options, _ := f.Options.(*SelectOptions)
|
||||
if options.MaxSelect <= 1 {
|
||||
if len(val) > 0 {
|
||||
return val[0]
|
||||
return val[len(val)-1] // the last selected
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -288,7 +302,7 @@ func (f *SchemaField) PrepareValue(value any) any {
|
||||
options, _ := f.Options.(*FileOptions)
|
||||
if options.MaxSelect <= 1 {
|
||||
if len(val) > 0 {
|
||||
return val[0]
|
||||
return val[len(val)-1] // the last selected
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -300,7 +314,7 @@ func (f *SchemaField) PrepareValue(value any) any {
|
||||
options, _ := f.Options.(*RelationOptions)
|
||||
if options.MaxSelect != nil && *options.MaxSelect <= 1 {
|
||||
if len(ids) > 0 {
|
||||
return ids[0]
|
||||
return ids[len(ids)-1] // the last selected
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -311,6 +325,46 @@ func (f *SchemaField) PrepareValue(value any) any {
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareValueWithModifier returns normalized and properly formatted field value
|
||||
// by "merging" baseValue with the modifierValue based on the specified modifier (+ or -).
|
||||
func (f *SchemaField) PrepareValueWithModifier(baseValue any, modifier string, modifierValue any) any {
|
||||
resolvedValue := baseValue
|
||||
|
||||
switch f.Type {
|
||||
case FieldTypeNumber:
|
||||
switch modifier {
|
||||
case FieldValueModifierAdd:
|
||||
resolvedValue = cast.ToFloat64(baseValue) + cast.ToFloat64(modifierValue)
|
||||
case FieldValueModifierSubtract:
|
||||
resolvedValue = cast.ToFloat64(baseValue) - cast.ToFloat64(modifierValue)
|
||||
}
|
||||
case FieldTypeSelect, FieldTypeRelation:
|
||||
switch modifier {
|
||||
case FieldValueModifierAdd:
|
||||
resolvedValue = append(
|
||||
list.ToUniqueStringSlice(baseValue),
|
||||
list.ToUniqueStringSlice(modifierValue)...,
|
||||
)
|
||||
case FieldValueModifierSubtract:
|
||||
resolvedValue = list.SubtractSlice(
|
||||
list.ToUniqueStringSlice(baseValue),
|
||||
list.ToUniqueStringSlice(modifierValue),
|
||||
)
|
||||
}
|
||||
case FieldTypeFile:
|
||||
// note: file for now supports only the subtract modifier
|
||||
switch modifier {
|
||||
case FieldValueModifierSubtract:
|
||||
resolvedValue = list.SubtractSlice(
|
||||
list.ToUniqueStringSlice(baseValue),
|
||||
list.ToUniqueStringSlice(modifierValue),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return f.PrepareValue(resolvedValue)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// FieldOptions interfaces that defines common methods that every field options struct has.
|
||||
|
||||
@@ -603,7 +603,7 @@ func TestSchemaFieldPrepareValue(t *testing.T) {
|
||||
{schema.SchemaField{Type: schema.FieldTypeSelect}, "", `""`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeSelect}, 123, `"123"`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeSelect}, "test", `"test"`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeSelect}, []string{"test1", "test2"}, `"test1"`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeSelect}, []string{"test1", "test2"}, `"test2"`},
|
||||
{
|
||||
// no values validation/filtering
|
||||
schema.SchemaField{
|
||||
@@ -680,7 +680,7 @@ func TestSchemaFieldPrepareValue(t *testing.T) {
|
||||
{schema.SchemaField{Type: schema.FieldTypeFile}, "", `""`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeFile}, 123, `"123"`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeFile}, "test", `"test"`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeFile}, []string{"test1", "test2"}, `"test1"`},
|
||||
{schema.SchemaField{Type: schema.FieldTypeFile}, []string{"test1", "test2"}, `"test2"`},
|
||||
// file (multiple)
|
||||
{
|
||||
schema.SchemaField{
|
||||
@@ -785,7 +785,7 @@ func TestSchemaFieldPrepareValue(t *testing.T) {
|
||||
{
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
[]string{"1ba88b4f-e9da-42f0-9764-9a55c953e724", "2ba88b4f-e9da-42f0-9764-9a55c953e724"},
|
||||
`"1ba88b4f-e9da-42f0-9764-9a55c953e724"`,
|
||||
`"2ba88b4f-e9da-42f0-9764-9a55c953e724"`,
|
||||
},
|
||||
// relation (multiple)
|
||||
{
|
||||
@@ -863,6 +863,696 @@ func TestSchemaFieldPrepareValue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchemaFieldPrepareValueWithModifier(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
field schema.SchemaField
|
||||
baseValue any
|
||||
modifier string
|
||||
modifierValue any
|
||||
expectJson string
|
||||
}{
|
||||
// text
|
||||
{
|
||||
"text with '+' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeText},
|
||||
"base",
|
||||
"+",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"text with '-' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeText},
|
||||
"base",
|
||||
"-",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"text with unknown modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeText},
|
||||
"base",
|
||||
"?",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"text cast check",
|
||||
schema.SchemaField{Type: schema.FieldTypeText},
|
||||
123,
|
||||
"?",
|
||||
"new",
|
||||
`"123"`,
|
||||
},
|
||||
|
||||
// number
|
||||
{
|
||||
"number with '+' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeNumber},
|
||||
1,
|
||||
"+",
|
||||
4,
|
||||
`5`,
|
||||
},
|
||||
{
|
||||
"number with '-' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeNumber},
|
||||
1,
|
||||
"-",
|
||||
4,
|
||||
`-3`,
|
||||
},
|
||||
{
|
||||
"number with unknown modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeNumber},
|
||||
"1",
|
||||
"?",
|
||||
4,
|
||||
`1`,
|
||||
},
|
||||
{
|
||||
"number cast check",
|
||||
schema.SchemaField{Type: schema.FieldTypeNumber},
|
||||
"test",
|
||||
"+",
|
||||
"4",
|
||||
`4`,
|
||||
},
|
||||
|
||||
// bool
|
||||
{
|
||||
"bool with '+' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeBool},
|
||||
true,
|
||||
"+",
|
||||
false,
|
||||
`true`,
|
||||
},
|
||||
{
|
||||
"bool with '-' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeBool},
|
||||
true,
|
||||
"-",
|
||||
false,
|
||||
`true`,
|
||||
},
|
||||
{
|
||||
"bool with unknown modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeBool},
|
||||
true,
|
||||
"?",
|
||||
false,
|
||||
`true`,
|
||||
},
|
||||
{
|
||||
"bool cast check",
|
||||
schema.SchemaField{Type: schema.FieldTypeBool},
|
||||
"true",
|
||||
"?",
|
||||
false,
|
||||
`true`,
|
||||
},
|
||||
|
||||
// email
|
||||
{
|
||||
"email with '+' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeEmail},
|
||||
"base",
|
||||
"+",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"email with '-' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeEmail},
|
||||
"base",
|
||||
"-",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"email with unknown modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeEmail},
|
||||
"base",
|
||||
"?",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"email cast check",
|
||||
schema.SchemaField{Type: schema.FieldTypeEmail},
|
||||
123,
|
||||
"?",
|
||||
"new",
|
||||
`"123"`,
|
||||
},
|
||||
|
||||
// url
|
||||
{
|
||||
"url with '+' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeUrl},
|
||||
"base",
|
||||
"+",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"url with '-' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeUrl},
|
||||
"base",
|
||||
"-",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"url with unknown modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeUrl},
|
||||
"base",
|
||||
"?",
|
||||
"new",
|
||||
`"base"`,
|
||||
},
|
||||
{
|
||||
"url cast check",
|
||||
schema.SchemaField{Type: schema.FieldTypeUrl},
|
||||
123,
|
||||
"-",
|
||||
"new",
|
||||
`"123"`,
|
||||
},
|
||||
|
||||
// date
|
||||
{
|
||||
"date with '+' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeDate},
|
||||
"2023-01-01 00:00:00.123",
|
||||
"+",
|
||||
"2023-02-01 00:00:00.456",
|
||||
`"2023-01-01 00:00:00.123Z"`,
|
||||
},
|
||||
{
|
||||
"date with '-' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeDate},
|
||||
"2023-01-01 00:00:00.123Z",
|
||||
"-",
|
||||
"2023-02-01 00:00:00.456Z",
|
||||
`"2023-01-01 00:00:00.123Z"`,
|
||||
},
|
||||
{
|
||||
"date with unknown modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeDate},
|
||||
"2023-01-01 00:00:00.123",
|
||||
"?",
|
||||
"2023-01-01 00:00:00.456",
|
||||
`"2023-01-01 00:00:00.123Z"`,
|
||||
},
|
||||
{
|
||||
"date cast check",
|
||||
schema.SchemaField{Type: schema.FieldTypeDate},
|
||||
1672524000, // 2022-12-31 22:00:00.000Z
|
||||
"+",
|
||||
100,
|
||||
`"2022-12-31 22:00:00.000Z"`,
|
||||
},
|
||||
|
||||
// json
|
||||
{
|
||||
"json with '+' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeJson},
|
||||
10,
|
||||
"+",
|
||||
5,
|
||||
`10`,
|
||||
},
|
||||
{
|
||||
"json with '+' modifier (slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeJson},
|
||||
[]string{"a", "b"},
|
||||
"+",
|
||||
"c",
|
||||
`["a","b"]`,
|
||||
},
|
||||
{
|
||||
"json with '-' modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeJson},
|
||||
10,
|
||||
"-",
|
||||
5,
|
||||
`10`,
|
||||
},
|
||||
{
|
||||
"json with '-' modifier (slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeJson},
|
||||
`["a","b"]`,
|
||||
"-",
|
||||
"c",
|
||||
`["a","b"]`,
|
||||
},
|
||||
{
|
||||
"json with unknown modifier",
|
||||
schema.SchemaField{Type: schema.FieldTypeJson},
|
||||
`"base"`,
|
||||
"?",
|
||||
`"new"`,
|
||||
`"base"`,
|
||||
},
|
||||
|
||||
// single select
|
||||
{
|
||||
"single select with '+' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"",
|
||||
"+",
|
||||
"b",
|
||||
`"b"`,
|
||||
},
|
||||
{
|
||||
"single select with '+' modifier (nonempty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"+",
|
||||
"b",
|
||||
`"b"`,
|
||||
},
|
||||
{
|
||||
"single select with '-' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"",
|
||||
"-",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single select with '-' modifier (nonempty base and empty modifier value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
"",
|
||||
`"a"`,
|
||||
},
|
||||
{
|
||||
"single select with '-' modifier (nonempty base and different value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
"b",
|
||||
`"a"`,
|
||||
},
|
||||
{
|
||||
"single select with '-' modifier (nonempty base and matching value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single select with '-' modifier (nonempty base and matching value in a slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
[]string{"b", "a", "c", "123"},
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single select with unknown modifier (nonempty)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 1}},
|
||||
"",
|
||||
"?",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
|
||||
// multi select
|
||||
{
|
||||
"multi select with '+' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
nil,
|
||||
"+",
|
||||
"b",
|
||||
`["b"]`,
|
||||
},
|
||||
{
|
||||
"multi select with '+' modifier (nonempty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
[]string{"a"},
|
||||
"+",
|
||||
[]string{"b", "c"},
|
||||
`["a","b","c"]`,
|
||||
},
|
||||
{
|
||||
"multi select with '+' modifier (nonempty base; already existing value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b"},
|
||||
"+",
|
||||
"b",
|
||||
`["a","b"]`,
|
||||
},
|
||||
{
|
||||
"multi select with '-' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
nil,
|
||||
"-",
|
||||
[]string{"a"},
|
||||
`[]`,
|
||||
},
|
||||
{
|
||||
"multi select with '-' modifier (nonempty base and empty modifier value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
"a",
|
||||
"-",
|
||||
"",
|
||||
`["a"]`,
|
||||
},
|
||||
{
|
||||
"multi select with '-' modifier (nonempty base and different value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
"a",
|
||||
"-",
|
||||
"b",
|
||||
`["a"]`,
|
||||
},
|
||||
{
|
||||
"multi select with '-' modifier (nonempty base and matching value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
"-",
|
||||
"c",
|
||||
`["a","b","d"]`,
|
||||
},
|
||||
{
|
||||
"multi select with '-' modifier (nonempty base and matching value in a slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
"-",
|
||||
[]string{"b", "a", "123"},
|
||||
`["c","d"]`,
|
||||
},
|
||||
{
|
||||
"multi select with unknown modifier (nonempty)",
|
||||
schema.SchemaField{Type: schema.FieldTypeSelect, Options: &schema.SelectOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b"},
|
||||
"?",
|
||||
"a",
|
||||
`["a","b"]`,
|
||||
},
|
||||
|
||||
// single relation
|
||||
{
|
||||
"single relation with '+' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"",
|
||||
"+",
|
||||
"b",
|
||||
`"b"`,
|
||||
},
|
||||
{
|
||||
"single relation with '+' modifier (nonempty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"a",
|
||||
"+",
|
||||
"b",
|
||||
`"b"`,
|
||||
},
|
||||
{
|
||||
"single relation with '-' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"",
|
||||
"-",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single relation with '-' modifier (nonempty base and empty modifier value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"a",
|
||||
"-",
|
||||
"",
|
||||
`"a"`,
|
||||
},
|
||||
{
|
||||
"single relation with '-' modifier (nonempty base and different value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"a",
|
||||
"-",
|
||||
"b",
|
||||
`"a"`,
|
||||
},
|
||||
{
|
||||
"single relation with '-' modifier (nonempty base and matching value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"a",
|
||||
"-",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single relation with '-' modifier (nonempty base and matching value in a slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"a",
|
||||
"-",
|
||||
[]string{"b", "a", "c", "123"},
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single relation with unknown modifier (nonempty)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation, Options: &schema.RelationOptions{MaxSelect: types.Pointer(1)}},
|
||||
"",
|
||||
"?",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
|
||||
// multi relation
|
||||
{
|
||||
"multi relation with '+' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
nil,
|
||||
"+",
|
||||
"b",
|
||||
`["b"]`,
|
||||
},
|
||||
{
|
||||
"multi relation with '+' modifier (nonempty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
[]string{"a"},
|
||||
"+",
|
||||
[]string{"b", "c"},
|
||||
`["a","b","c"]`,
|
||||
},
|
||||
{
|
||||
"multi relation with '+' modifier (nonempty base; already existing value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
[]string{"a", "b"},
|
||||
"+",
|
||||
"b",
|
||||
`["a","b"]`,
|
||||
},
|
||||
{
|
||||
"multi relation with '-' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
nil,
|
||||
"-",
|
||||
[]string{"a"},
|
||||
`[]`,
|
||||
},
|
||||
{
|
||||
"multi relation with '-' modifier (nonempty base and empty modifier value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
"a",
|
||||
"-",
|
||||
"",
|
||||
`["a"]`,
|
||||
},
|
||||
{
|
||||
"multi relation with '-' modifier (nonempty base and different value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
"a",
|
||||
"-",
|
||||
"b",
|
||||
`["a"]`,
|
||||
},
|
||||
{
|
||||
"multi relation with '-' modifier (nonempty base and matching value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
"-",
|
||||
"c",
|
||||
`["a","b","d"]`,
|
||||
},
|
||||
{
|
||||
"multi relation with '-' modifier (nonempty base and matching value in a slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
"-",
|
||||
[]string{"b", "a", "123"},
|
||||
`["c","d"]`,
|
||||
},
|
||||
{
|
||||
"multi relation with unknown modifier (nonempty)",
|
||||
schema.SchemaField{Type: schema.FieldTypeRelation},
|
||||
[]string{"a", "b"},
|
||||
"?",
|
||||
"a",
|
||||
`["a","b"]`,
|
||||
},
|
||||
|
||||
// single file
|
||||
{
|
||||
"single file with '+' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"",
|
||||
"+",
|
||||
"b",
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single file with '+' modifier (nonempty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"+",
|
||||
"b",
|
||||
`"a"`,
|
||||
},
|
||||
{
|
||||
"single file with '-' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"",
|
||||
"-",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single file with '-' modifier (nonempty base and empty modifier value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
"",
|
||||
`"a"`,
|
||||
},
|
||||
{
|
||||
"single file with '-' modifier (nonempty base and different value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
"b",
|
||||
`"a"`,
|
||||
},
|
||||
{
|
||||
"single file with '-' modifier (nonempty base and matching value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single file with '-' modifier (nonempty base and matching value in a slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"a",
|
||||
"-",
|
||||
[]string{"b", "a", "c", "123"},
|
||||
`""`,
|
||||
},
|
||||
{
|
||||
"single file with unknown modifier (nonempty)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 1}},
|
||||
"",
|
||||
"?",
|
||||
"a",
|
||||
`""`,
|
||||
},
|
||||
|
||||
// multi file
|
||||
{
|
||||
"multi file with '+' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
nil,
|
||||
"+",
|
||||
"b",
|
||||
`[]`,
|
||||
},
|
||||
{
|
||||
"multi file with '+' modifier (nonempty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
[]string{"a"},
|
||||
"+",
|
||||
[]string{"b", "c"},
|
||||
`["a"]`,
|
||||
},
|
||||
{
|
||||
"multi file with '+' modifier (nonempty base; already existing value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b"},
|
||||
"+",
|
||||
"b",
|
||||
`["a","b"]`,
|
||||
},
|
||||
{
|
||||
"multi file with '-' modifier (empty base)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
nil,
|
||||
"-",
|
||||
[]string{"a"},
|
||||
`[]`,
|
||||
},
|
||||
{
|
||||
"multi file with '-' modifier (nonempty base and empty modifier value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
"a",
|
||||
"-",
|
||||
"",
|
||||
`["a"]`,
|
||||
},
|
||||
{
|
||||
"multi file with '-' modifier (nonempty base and different value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
"a",
|
||||
"-",
|
||||
"b",
|
||||
`["a"]`,
|
||||
},
|
||||
{
|
||||
"multi file with '-' modifier (nonempty base and matching value)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
"-",
|
||||
"c",
|
||||
`["a","b","d"]`,
|
||||
},
|
||||
{
|
||||
"multi file with '-' modifier (nonempty base and matching value in a slice)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
"-",
|
||||
[]string{"b", "a", "123"},
|
||||
`["c","d"]`,
|
||||
},
|
||||
{
|
||||
"multi file with unknown modifier (nonempty)",
|
||||
schema.SchemaField{Type: schema.FieldTypeFile, Options: &schema.FileOptions{MaxSelect: 10}},
|
||||
[]string{"a", "b"},
|
||||
"?",
|
||||
"a",
|
||||
`["a","b"]`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
result := s.field.PrepareValueWithModifier(s.baseValue, s.modifier, s.modifierValue)
|
||||
|
||||
encoded, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
t.Fatalf("[%s] %v", s.name, err)
|
||||
}
|
||||
|
||||
if string(encoded) != s.expectJson {
|
||||
t.Fatalf("[%s], Expected %v, got %v", s.name, s.expectJson, string(encoded))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
type fieldOptionsScenario struct {
|
||||
@@ -1306,7 +1996,7 @@ func TestRelationOptionsValidate(t *testing.T) {
|
||||
[]string{"maxSelect"},
|
||||
},
|
||||
{
|
||||
"MaxSelect > 0 && non-empty CollectionId",
|
||||
"MaxSelect > 0 && nonempty CollectionId",
|
||||
schema.RelationOptions{
|
||||
CollectionId: "abc",
|
||||
MaxSelect: types.Pointer(1),
|
||||
|
||||
Reference in New Issue
Block a user