Repository: milvus-io/milvus-sdk-go
Pull request #514 (2023-07-14 03:46:28)

Support default value
Signed-off-by: lixinguo [xinguo.li@zilliz.com](mailto:xinguo.li@zilliz.com)
https://github.com/milvus-io/milvus/issues/23337
/kind improvement

sre-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/514#" title="Author self-approved">smellthemoon</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **congqixia** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @congqixia` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["congqixia"]} -->
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/514?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) Report
> Merging [#514](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/514?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) (1e7f7ea) into [master](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/commit/565c5e3e4acf2c83d71e9846429dd8bb5b1328dc?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) (565c5e3) will **increase** coverage by `0.01%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/514/graphs/tree.svg?width=650&height=150&src=pr&token=WJK43PV390&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io)](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/514?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io)

```diff
@@            Coverage Diff             @@
##           master     #514      +/-   ##
==========================================
+ Coverage   83.62%   83.64%   +0.01%     
==========================================
  Files          38       38              
  Lines        3383     3387       +4     
==========================================
+ Hits         2829     2833       +4     
  Misses        447      447              
  Partials      107      107              
```


| [Impacted Files](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/514?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) | Coverage Δ | |
|---|---|---|
| [entity/schema.go](https://app.codecov.io/gh/milvus-io/milvus-sdk-go/pull/514?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io#diff-ZW50aXR5L3NjaGVtYS5nbw==) | `94.28% <100.00%> (+0.13%)` | :arrow_up: |

sre-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/514#pullrequestreview-1534015852" title="LGTM">congqixia</a>*, *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/514#" title="Author self-approved">smellthemoon</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)~~ [congqixia]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/client/insert.go b/client/insert.go
index 8f756c9..2d78385 100644
--- a/client/insert.go
+++ b/client/insert.go
@@ -140,6 +140,15 @@ func (c *GrpcClient) processInsertColumns(colSchema *entity.Schema, columns ...e
 		_, has := mNameColumn[field.Name]
 		if !has &&
 			!field.AutoID && !field.IsDynamic {
+			if field.DefaultValue != nil {
+				emptyColumn, err := entity.DefaultValueColumn(field.Name, field.DataType)
+				// no err will be throw
+				if err != nil {
+					return nil, 0, fmt.Errorf("empty column fail to create, field name:%s ", field.Name)
+				}
+				mNameColumn[field.Name] = emptyColumn
+				continue
+			}
 			return nil, 0, fmt.Errorf("field %s not passed", field.Name)
 		}
 	}
diff --git a/entity/columns.go b/entity/columns.go
index d88fb3d..9c1ebf7 100644
--- a/entity/columns.go
+++ b/entity/columns.go
@@ -357,3 +357,32 @@ func FieldDataVector(fd *schema.FieldData) (Column, error) {
 		return nil, errors.New("unsupported data type")
 	}
 }
+
+// defaultValueColumn will return the empty scalars column which will be fill with default value
+func DefaultValueColumn(name string, dataType FieldType) (Column, error) {
+	switch dataType {
+	case FieldTypeBool:
+		return NewColumnBool(name, nil), nil
+	case FieldTypeInt8:
+		return NewColumnInt8(name, nil), nil
+	case FieldTypeInt16:
+		return NewColumnInt16(name, nil), nil
+	case FieldTypeInt32:
+		return NewColumnInt32(name, nil), nil
+	case FieldTypeInt64:
+		return NewColumnInt64(name, nil), nil
+	case FieldTypeFloat:
+		return NewColumnFloat(name, nil), nil
+	case FieldTypeDouble:
+		return NewColumnDouble(name, nil), nil
+	case FieldTypeString:
+		return NewColumnString(name, nil), nil
+	case FieldTypeVarChar:
+		return NewColumnVarChar(name, nil), nil
+	case FieldTypeJSON:
+		return NewColumnJSONBytes(name, nil), nil
+
+	default:
+		return nil, fmt.Errorf("default value unsupported data type %s", dataType)
+	}
+}
diff --git a/entity/schema.go b/entity/schema.go
index 9dc79ee..58c8d33 100644
--- a/entity/schema.go
+++ b/entity/schema.go
@@ -137,6 +137,7 @@ type Field struct {
 	IndexParams    map[string]string
 	IsDynamic      bool
 	IsPartitionKey bool
+	DefaultValue   *schema.ValueField
 }
 
 // ProtoMessage generates corresponding FieldSchema
@@ -152,6 +153,7 @@ func (f *Field) ProtoMessage() *schema.FieldSchema {
 		IndexParams:    MapKvPairs(f.IndexParams),
 		IsDynamic:      f.IsDynamic,
 		IsPartitionKey: f.IsPartitionKey,
+		DefaultValue:   f.DefaultValue,
 	}
 }
 
@@ -198,6 +200,60 @@ func (f *Field) WithIsPartitionKey(isPartitionKey bool) *Field {
 	return f
 }
 
+func (f *Field) WithDefaultValueBool(defaultValue bool) *Field {
+	f.DefaultValue = &schema.ValueField{
+		Data: &schema.ValueField_BoolData{
+			BoolData: defaultValue,
+		},
+	}
+	return f
+}
+
+func (f *Field) WithDefaultValueInt(defaultValue int32) *Field {
+	f.DefaultValue = &schema.ValueField{
+		Data: &schema.ValueField_IntData{
+			IntData: defaultValue,
+		},
+	}
+	return f
+}
+
+func (f *Field) WithDefaultValueLong(defaultValue int64) *Field {
+	f.DefaultValue = &schema.ValueField{
+		Data: &schema.ValueField_LongData{
+			LongData: defaultValue,
+		},
+	}
+	return f
+}
+
+func (f *Field) WithDefaultValueFloat(defaultValue float32) *Field {
+	f.DefaultValue = &schema.ValueField{
+		Data: &schema.ValueField_FloatData{
+			FloatData: defaultValue,
+		},
+	}
+	return f
+}
+
+func (f *Field) WithDefaultValueDouble(defaultValue float64) *Field {
+	f.DefaultValue = &schema.ValueField{
+		Data: &schema.ValueField_DoubleData{
+			DoubleData: defaultValue,
+		},
+	}
+	return f
+}
+
+func (f *Field) WithDefaultValueString(defaultValue string) *Field {
+	f.DefaultValue = &schema.ValueField{
+		Data: &schema.ValueField_StringData{
+			StringData: defaultValue,
+		},
+	}
+	return f
+}
+
 func (f *Field) WithTypeParams(key string, value string) *Field {
 	if f.TypeParams == nil {
 		f.TypeParams = make(map[string]string)
@@ -234,6 +290,7 @@ func (f *Field) ReadProto(p *schema.FieldSchema) *Field {
 	f.IndexParams = KvPairsMap(p.GetIndexParams())
 	f.IsDynamic = p.GetIsDynamic()
 	f.IsPartitionKey = p.GetIsPartitionKey()
+	f.DefaultValue = p.GetDefaultValue()
 
 	return f
 }


Test patch:
diff --git a/client/insert_test.go b/client/insert_test.go
index fc78d34..70f7a54 100644
--- a/client/insert_test.go
+++ b/client/insert_test.go
@@ -64,7 +64,7 @@ func (s *InsertSuite) TestInsertFail() {
 		s.Error(err)
 	})
 
-	s.Run("missing_field", func() {
+	s.Run("missing_field_without_default_value", func() {
 		defer s.resetMock()
 		s.setupHasCollection(testCollectionName)
 		s.setupHasPartition(testCollectionName, "partition_1")
@@ -267,6 +267,38 @@ func (s *InsertSuite) TestInsertSuccess() {
 		s.NoError(err)
 		s.Equal(1, r.Len())
 	})
+
+	s.Run("missing_field_with_default_value", func() {
+		defer s.resetMock()
+		s.setupHasCollection(testCollectionName)
+		s.setupHasPartition(testCollectionName, "partition_1")
+
+		s.setupDescribeCollection(testCollectionName, entity.NewSchema().
+			WithField(entity.NewField().WithIsPrimaryKey(true).WithIsAutoID(true).WithName("ID").WithDataType(entity.FieldTypeInt64)).
+			WithField(entity.NewField().WithName("default_value").WithDataType(entity.FieldTypeInt64).WithDefaultValueLong(1)).
+			WithField(entity.NewField().WithName("vector").WithDataType(entity.FieldTypeFloatVector).WithTypeParams(entity.TypeParamDim, "128")),
+		)
+
+		s.mock.EXPECT().Insert(mock.Anything, mock.AnythingOfType("*milvuspb.InsertRequest")).
+			Run(func(ctx context.Context, req *server.InsertRequest) {
+				s.Equal(2, len(req.GetFieldsData()))
+			}).Return(&server.MutationResult{
+			Status: &common.Status{},
+			IDs: &schema.IDs{
+				IdField: &schema.IDs_IntId{
+					IntId: &schema.LongArray{
+						Data: []int64{1},
+					},
+				},
+			},
+		}, nil)
+
+		r, err := c.Insert(ctx, testCollectionName, "partition_1",
+			entity.NewColumnFloatVector("vector", 128, generateFloatVector(1, 128)),
+		)
+		s.NoError(err)
+		s.Equal(1, r.Len())
+	})
 }
 
 func TestGrpcInsert(t *testing.T) {
diff --git a/entity/schema_test.go b/entity/schema_test.go
index 81d3b08..82054a2 100644
--- a/entity/schema_test.go
+++ b/entity/schema_test.go
@@ -25,6 +25,12 @@ func TestFieldSchema(t *testing.T) {
 		NewField().WithName("int_field").WithDataType(FieldTypeInt64).WithIsAutoID(true).WithIsPrimaryKey(true).WithDescription("int_field desc"),
 		NewField().WithName("string_field").WithDataType(FieldTypeString).WithIsAutoID(false).WithIsPrimaryKey(true).WithIsDynamic(false).WithTypeParams("max_len", "32").WithDescription("string_field desc"),
 		NewField().WithName("partition_key").WithDataType(FieldTypeInt32).WithIsPartitionKey(true),
+		NewField().WithName("default_value_bool").WithDataType(FieldTypeBool).WithDefaultValueBool(true),
+		NewField().WithName("default_value_int").WithDataType(FieldTypeInt32).WithDefaultValueInt(1),
+		NewField().WithName("default_value_long").WithDataType(FieldTypeInt64).WithDefaultValueLong(1),
+		NewField().WithName("default_value_float").WithDataType(FieldTypeFloat).WithDefaultValueFloat(1),
+		NewField().WithName("default_value_double").WithDataType(FieldTypeDouble).WithDefaultValueDouble(1),
+		NewField().WithName("default_value_string").WithDataType(FieldTypeString).WithDefaultValueString("a"),
 	}
 
 	for _, field := range fields {
@@ -35,6 +41,7 @@ func TestFieldSchema(t *testing.T) {
 		assert.Equal(t, field.AutoID, fieldSchema.GetAutoID())
 		assert.Equal(t, field.PrimaryKey, fieldSchema.GetIsPrimaryKey())
 		assert.Equal(t, field.IsPartitionKey, fieldSchema.GetIsPartitionKey())
+		assert.Equal(t, field.DefaultValue, fieldSchema.GetDefaultValue())
 		assert.Equal(t, field.IsDynamic, fieldSchema.GetIsDynamic())
 		assert.Equal(t, field.Description, fieldSchema.GetDescription())
 		assert.Equal(t, field.TypeParams, KvPairsMap(fieldSchema.GetTypeParams()))
@@ -49,6 +56,7 @@ func TestFieldSchema(t *testing.T) {
 		assert.Equal(t, field.Description, nf.Description)
 		assert.Equal(t, field.IsDynamic, nf.IsDynamic)
 		assert.Equal(t, field.IsPartitionKey, nf.IsPartitionKey)
+		assert.Equal(t, field.DefaultValue, nf.DefaultValue)
 		assert.EqualValues(t, field.TypeParams, nf.TypeParams)
 	}