github.com/weaviate/weaviate@v1.24.6/entities/schema/data_types_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package schema
    13  
    14  import (
    15  	"fmt"
    16  	"testing"
    17  
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/require"
    20  	"github.com/weaviate/weaviate/entities/models"
    21  )
    22  
    23  func TestDetectPrimitiveTypes(t *testing.T) {
    24  	s := Empty()
    25  
    26  	for _, dt := range append(PrimitiveDataTypes, DeprecatedPrimitiveDataTypes...) {
    27  		pdt, err := s.FindPropertyDataType(dt.PropString())
    28  
    29  		assert.Nil(t, err)
    30  		assert.True(t, pdt.IsPrimitive())
    31  		assert.Equal(t, dt, pdt.AsPrimitive())
    32  
    33  		assert.False(t, pdt.IsNested())
    34  		assert.False(t, pdt.IsReference())
    35  	}
    36  }
    37  
    38  func TestDetectNestedTypes(t *testing.T) {
    39  	s := Empty()
    40  
    41  	for _, dt := range NestedDataTypes {
    42  		ndt, err := s.FindPropertyDataType(dt.PropString())
    43  
    44  		assert.Nil(t, err)
    45  		assert.True(t, ndt.IsNested())
    46  		assert.Equal(t, dt, ndt.AsNested())
    47  
    48  		assert.False(t, ndt.IsPrimitive())
    49  		assert.False(t, ndt.IsReference())
    50  	}
    51  }
    52  
    53  func TestExistingClassSingleRef(t *testing.T) {
    54  	className := "ExistingClass"
    55  	s := Empty()
    56  	s.Objects.Classes = []*models.Class{{Class: className}}
    57  
    58  	pdt, err := s.FindPropertyDataType([]string{className})
    59  
    60  	assert.Nil(t, err)
    61  	assert.True(t, pdt.IsReference())
    62  	assert.True(t, pdt.ContainsClass(ClassName(className)))
    63  }
    64  
    65  func TestNonExistingClassSingleRef(t *testing.T) {
    66  	className := "NonExistingClass"
    67  	s := Empty()
    68  
    69  	pdt, err := s.FindPropertyDataType([]string{className})
    70  
    71  	assert.EqualError(t, err, ErrRefToNonexistentClass.Error())
    72  	assert.Nil(t, pdt)
    73  }
    74  
    75  func TestNonExistingClassRelaxedCrossValidation(t *testing.T) {
    76  	className := "NonExistingClass"
    77  	s := Empty()
    78  
    79  	pdt, err := s.FindPropertyDataTypeWithRefs([]string{className}, true, ClassName("AnotherNonExistingClass"))
    80  
    81  	assert.Nil(t, err)
    82  	assert.True(t, pdt.IsReference())
    83  	assert.True(t, pdt.ContainsClass(ClassName(className)))
    84  }
    85  
    86  func TestNonExistingClassPropertyBelongsTo(t *testing.T) {
    87  	className := "NonExistingClass"
    88  	s := Empty()
    89  
    90  	pdt, err := s.FindPropertyDataTypeWithRefs([]string{className}, false, ClassName(className))
    91  
    92  	assert.Nil(t, err)
    93  	assert.True(t, pdt.IsReference())
    94  	assert.True(t, pdt.ContainsClass(ClassName(className)))
    95  }
    96  
    97  func TestGetPropertyDataType(t *testing.T) {
    98  	class := &models.Class{Class: "TestClass"}
    99  	dataTypes := []string{
   100  		"string", "text", "int", "number", "boolean",
   101  		"date", "geoCoordinates", "phoneNumber", "blob", "Ref", "invalid",
   102  		"string[]", "text[]", "int[]", "number[]", "boolean[]", "date[]",
   103  		"uuid", "uuid[]",
   104  
   105  		"object", "object[]",
   106  	}
   107  	class.Properties = make([]*models.Property, len(dataTypes))
   108  	for i, dtString := range dataTypes {
   109  		class.Properties[i] = &models.Property{
   110  			Name:     dtString + "Prop",
   111  			DataType: []string{dtString},
   112  		}
   113  	}
   114  
   115  	type test struct {
   116  		propName         string
   117  		expectedDataType *DataType
   118  		expectedErr      error
   119  	}
   120  
   121  	tests := []test{
   122  		{
   123  			propName:         "stringProp",
   124  			expectedDataType: ptDataType(DataTypeString),
   125  		},
   126  		{
   127  			propName:         "textProp",
   128  			expectedDataType: ptDataType(DataTypeText),
   129  		},
   130  		{
   131  			propName:         "numberProp",
   132  			expectedDataType: ptDataType(DataTypeNumber),
   133  		},
   134  		{
   135  			propName:         "intProp",
   136  			expectedDataType: ptDataType(DataTypeInt),
   137  		},
   138  		{
   139  			propName:         "booleanProp",
   140  			expectedDataType: ptDataType(DataTypeBoolean),
   141  		},
   142  		{
   143  			propName:         "dateProp",
   144  			expectedDataType: ptDataType(DataTypeDate),
   145  		},
   146  		{
   147  			propName:         "phoneNumberProp",
   148  			expectedDataType: ptDataType(DataTypePhoneNumber),
   149  		},
   150  		{
   151  			propName:         "geoCoordinatesProp",
   152  			expectedDataType: ptDataType(DataTypeGeoCoordinates),
   153  		},
   154  		{
   155  			propName:         "blobProp",
   156  			expectedDataType: ptDataType(DataTypeBlob),
   157  		},
   158  		{
   159  			propName:         "string[]Prop",
   160  			expectedDataType: ptDataType(DataTypeStringArray),
   161  		},
   162  		{
   163  			propName:         "text[]Prop",
   164  			expectedDataType: ptDataType(DataTypeTextArray),
   165  		},
   166  		{
   167  			propName:         "int[]Prop",
   168  			expectedDataType: ptDataType(DataTypeIntArray),
   169  		},
   170  		{
   171  			propName:         "number[]Prop",
   172  			expectedDataType: ptDataType(DataTypeNumberArray),
   173  		},
   174  		{
   175  			propName:         "boolean[]Prop",
   176  			expectedDataType: ptDataType(DataTypeBooleanArray),
   177  		},
   178  		{
   179  			propName:         "date[]Prop",
   180  			expectedDataType: ptDataType(DataTypeDateArray),
   181  		},
   182  		{
   183  			propName:         "uuidProp",
   184  			expectedDataType: ptDataType(DataTypeUUID),
   185  		},
   186  		{
   187  			propName:         "uuid[]Prop",
   188  			expectedDataType: ptDataType(DataTypeUUIDArray),
   189  		},
   190  		{
   191  			propName:         "objectProp",
   192  			expectedDataType: ptDataType(DataTypeObject),
   193  		},
   194  		{
   195  			propName:         "object[]Prop",
   196  			expectedDataType: ptDataType(DataTypeObjectArray),
   197  		},
   198  		{
   199  			propName:         "RefProp",
   200  			expectedDataType: ptDataType(DataTypeCRef),
   201  		},
   202  		{
   203  			propName:         "wrongProp",
   204  			expectedDataType: nil,
   205  			expectedErr:      fmt.Errorf("no such prop with name 'wrongProp' found in class 'TestClass' in the schema. Check your schema files for which properties in this class are available"),
   206  		},
   207  		{
   208  			propName:         "invalidProp",
   209  			expectedDataType: nil,
   210  			expectedErr:      fmt.Errorf("given value-DataType does not exist."),
   211  		},
   212  	}
   213  
   214  	for _, test := range tests {
   215  		t.Run(test.propName, func(t *testing.T) {
   216  			dt, err := GetPropertyDataType(class, test.propName)
   217  			require.Equal(t, test.expectedErr, err)
   218  			assert.Equal(t, test.expectedDataType, dt)
   219  		})
   220  	}
   221  }
   222  
   223  func Test_DataType_AsPrimitive(t *testing.T) {
   224  	type testCase struct {
   225  		name                string
   226  		inputDataType       []string
   227  		expectedDataType    DataType
   228  		expectedIsPrimitive bool
   229  	}
   230  
   231  	runTestCases := func(t *testing.T, testCases []testCase) {
   232  		for _, tc := range testCases {
   233  			t.Run(tc.name, func(t *testing.T) {
   234  				dataType, ok := AsPrimitive(tc.inputDataType)
   235  				assert.Equal(t, tc.expectedDataType, dataType)
   236  				assert.Equal(t, tc.expectedIsPrimitive, ok)
   237  			})
   238  		}
   239  	}
   240  
   241  	t.Run("is primitive data type", func(t *testing.T) {
   242  		testCases := []testCase{}
   243  		for _, dt := range append(PrimitiveDataTypes, DeprecatedPrimitiveDataTypes...) {
   244  			inputDataType := dt.PropString()
   245  			testCases = append(testCases, testCase{
   246  				name:                fmt.Sprintf("%v", inputDataType),
   247  				inputDataType:       inputDataType,
   248  				expectedDataType:    dt,
   249  				expectedIsPrimitive: true,
   250  			})
   251  		}
   252  
   253  		runTestCases(t, testCases)
   254  	})
   255  
   256  	t.Run("is empty data type", func(t *testing.T) {
   257  		testCases := []testCase{}
   258  		for _, dtStr := range []string{""} {
   259  			inputDataType := []string{dtStr}
   260  			testCases = append(testCases, testCase{
   261  				name:                fmt.Sprintf("%v", inputDataType),
   262  				inputDataType:       inputDataType,
   263  				expectedDataType:    "",
   264  				expectedIsPrimitive: true,
   265  			})
   266  		}
   267  
   268  		runTestCases(t, testCases)
   269  	})
   270  
   271  	t.Run("is non existent data type", func(t *testing.T) {
   272  		testCases := []testCase{}
   273  		for _, dtStr := range []string{"non-existent"} {
   274  			inputDataType := []string{dtStr}
   275  			testCases = append(testCases, testCase{
   276  				name:                fmt.Sprintf("%v", inputDataType),
   277  				inputDataType:       inputDataType,
   278  				expectedDataType:    "",
   279  				expectedIsPrimitive: false,
   280  			})
   281  		}
   282  
   283  		runTestCases(t, testCases)
   284  	})
   285  
   286  	t.Run("is nested data type", func(t *testing.T) {
   287  		testCases := []testCase{}
   288  		for _, dt := range NestedDataTypes {
   289  			inputDataType := dt.PropString()
   290  			testCases = append(testCases, testCase{
   291  				name:                fmt.Sprintf("%v", inputDataType),
   292  				inputDataType:       inputDataType,
   293  				expectedDataType:    "",
   294  				expectedIsPrimitive: false,
   295  			})
   296  		}
   297  
   298  		runTestCases(t, testCases)
   299  	})
   300  
   301  	t.Run("is reference data type", func(t *testing.T) {
   302  		testCases := []testCase{}
   303  		for _, inputDataType := range [][]string{
   304  			{"SomeClass"},
   305  			{"SomeOtherClass", "AndAnotherOne"},
   306  		} {
   307  			testCases = append(testCases, testCase{
   308  				name:                fmt.Sprintf("%v", inputDataType),
   309  				inputDataType:       inputDataType,
   310  				expectedDataType:    "",
   311  				expectedIsPrimitive: false,
   312  			})
   313  		}
   314  
   315  		runTestCases(t, testCases)
   316  	})
   317  }
   318  
   319  func Test_DataType_AsNested(t *testing.T) {
   320  	type testCase struct {
   321  		name             string
   322  		inputDataType    []string
   323  		expectedDataType DataType
   324  		expectedIsNested bool
   325  	}
   326  
   327  	runTestCases := func(t *testing.T, testCases []testCase) {
   328  		for _, tc := range testCases {
   329  			t.Run(tc.name, func(t *testing.T) {
   330  				dataType, ok := AsNested(tc.inputDataType)
   331  				assert.Equal(t, tc.expectedDataType, dataType)
   332  				assert.Equal(t, tc.expectedIsNested, ok)
   333  			})
   334  		}
   335  	}
   336  
   337  	t.Run("is nested data type", func(t *testing.T) {
   338  		testCases := []testCase{}
   339  		for _, dt := range NestedDataTypes {
   340  			inputDataType := dt.PropString()
   341  			testCases = append(testCases, testCase{
   342  				name:             fmt.Sprintf("%v", inputDataType),
   343  				inputDataType:    inputDataType,
   344  				expectedDataType: dt,
   345  				expectedIsNested: true,
   346  			})
   347  		}
   348  
   349  		runTestCases(t, testCases)
   350  	})
   351  
   352  	t.Run("is empty data type", func(t *testing.T) {
   353  		testCases := []testCase{}
   354  		for _, dtStr := range []string{""} {
   355  			inputDataType := []string{dtStr}
   356  			testCases = append(testCases, testCase{
   357  				name:             fmt.Sprintf("%v", inputDataType),
   358  				inputDataType:    inputDataType,
   359  				expectedDataType: "",
   360  				expectedIsNested: false,
   361  			})
   362  		}
   363  
   364  		runTestCases(t, testCases)
   365  	})
   366  
   367  	t.Run("is non existent data type", func(t *testing.T) {
   368  		testCases := []testCase{}
   369  		for _, dtStr := range []string{"non-existent"} {
   370  			inputDataType := []string{dtStr}
   371  			testCases = append(testCases, testCase{
   372  				name:             fmt.Sprintf("%v", inputDataType),
   373  				inputDataType:    inputDataType,
   374  				expectedDataType: "",
   375  				expectedIsNested: false,
   376  			})
   377  		}
   378  
   379  		runTestCases(t, testCases)
   380  	})
   381  
   382  	t.Run("is primitive data type", func(t *testing.T) {
   383  		testCases := []testCase{}
   384  		for _, dt := range append(PrimitiveDataTypes, DeprecatedPrimitiveDataTypes...) {
   385  			inputDataType := dt.PropString()
   386  			testCases = append(testCases, testCase{
   387  				name:             fmt.Sprintf("%v", inputDataType),
   388  				inputDataType:    inputDataType,
   389  				expectedDataType: "",
   390  				expectedIsNested: false,
   391  			})
   392  		}
   393  
   394  		runTestCases(t, testCases)
   395  	})
   396  
   397  	t.Run("is reference data type", func(t *testing.T) {
   398  		testCases := []testCase{}
   399  		for _, inputDataType := range [][]string{
   400  			{"SomeClass"},
   401  			{"SomeOtherClass", "AndAnotherOne"},
   402  		} {
   403  			testCases = append(testCases, testCase{
   404  				name:             fmt.Sprintf("%v", inputDataType),
   405  				inputDataType:    inputDataType,
   406  				expectedDataType: "",
   407  				expectedIsNested: false,
   408  			})
   409  		}
   410  
   411  		runTestCases(t, testCases)
   412  	})
   413  }
   414  
   415  func ptDataType(dt DataType) *DataType {
   416  	return &dt
   417  }