Repository: oom-ai/oomstore
Pull request #920 (2022-01-07 02:44:09)

test: update config sources


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e9cbc72e..d4884d90 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -48,7 +48,7 @@ jobs:
   test:
     runs-on: ubuntu-latest
     env:
-      oomplay-version: '0.6.8'
+      oomplay-version: '0.5.0'
     steps:
     - uses: actions/checkout@v2
     - uses: satackey/action-docker-layer-caching@v0.0.11
diff --git a/Makefile b/Makefile
index 5fc95036..31b4dbbd 100644
--- a/Makefile
+++ b/Makefile
@@ -56,16 +56,9 @@ oomcli:
 oomagent: codegen
 	$(MAKE) -C oomagent build
 
-UNAME_S := $(shell uname -s)
-ifeq ($(UNAME_S),Linux)
-	TEST_PLAYGROUNDS := redis postgres mysql dynamodb cassandra tidb tikv sqlite
-else
-	TEST_PLAYGROUNDS := redis postgres mysql dynamodb cassandra tidbext tikvext sqlite
-endif
-
 .PHONY: test
 test: codegen
-	@oomplay init $(TEST_PLAYGROUNDS) -j 16
+	@oomplay init $$(oomplay list) -j 16
 	@go test -race -coverprofile=coverage.out -covermode=atomic ./...
 
 .PHONY: integration-test
diff --git a/README.md b/README.md
index 218d7105..a5909324 100644
--- a/README.md
+++ b/README.md
@@ -28,11 +28,11 @@
 
 ## Overview
 
-oomstore allows you to:
+The name "OOM" is derived from **O**nline Store, **O**ffline Store, and **M**etadata Store that put together oomstore.
+It allows you to define features with YAML,
+store features in databases of choice,
+and retrieve features in both online and offline use cases, fast.
 
-- Define features with YAML
-- Store features in databases of choice (see [supported databases](https://oom.ai/docs/supported-databases))
-- Retrieve features for both online and offline use, fast (see [benchmark](https://oom.ai/docs/benchmark))
 
 Please see our [docs](https://oom.ai/docs) for more details.
 
@@ -62,17 +62,17 @@ Compared to other feature store implementations, oomstore has its edges:
 2. `oomcli init` to initialize oomstore. Make sure there is a `~/.config/oomstore/config.yaml` as below.
 
 ```yaml
-online-store:
-  sqlite:
-    db-file: /tmp/oomstore.db
-
-offline-store:
-  sqlite:
-    db-file: /tmp/oomstore.db
-
-metadata-store:
-  sqlite:
-    db-file: /tmp/oomstore.db
+store: &pg
+  postgres:
+    host: 127.0.0.1
+    port: 5432
+    user: postgres
+    password: postgres
+    database: oomstore
+
+online-store: *pg
+offline-store: *pg
+metadata-store: *pg
 ```
 
 3. `oomcli apply -f config.yaml` to register metadata. See config.yaml below.
@@ -80,7 +80,6 @@ metadata-store:
 ```yaml
 kind: Entity
 name: user
-length: 8
 description: 'user ID'
 groups:
 - name: account
@@ -130,47 +129,48 @@ oomcli sync --revision-id 2
 ```bash
 oomcli get online \
   --entity-key 1006 \
-  --feature account.state,account.credit_score,account.account_age_days,account.has_2fa_installed,transaction_stats.transaction_count_7d,transaction_stats.transaction_count_30d
+  --feature state,credit_score,account_age_days,has_2fa_installed,transaction_count_7d,transaction_count_30d
 ```
 
 ```text
-+------+---------------+----------------------+--------------------------+---------------------------+----------------------------------------+-----------------------------------------+
-| user | account.state | account.credit_score | account.account_age_days | account.has_2fa_installed | transaction_stats.transaction_count_7d | transaction_stats.transaction_count_30d |
-+------+---------------+----------------------+--------------------------+---------------------------+----------------------------------------+-----------------------------------------+
-| 1006 | Louisiana     |                  710 |                       32 | false                     |                                      8 |                                      22 |
-+------+---------------+----------------------+--------------------------+---------------------------+----------------------------------------+-----------------------------------------+
++------+-----------+--------------+------------------+-------------------+----------------------+-----------------------+
+| user |   state   | credit_score | account_age_days | has_2fa_installed | transaction_count_7d | transaction_count_30d |
++------+-----------+--------------+------------------+-------------------+----------------------+-----------------------+
+| 1006 | Louisiana |          710 |               32 | false             |                    8 |                    22 |
++------+-----------+--------------+------------------+-------------------+----------------------+-----------------------+
 ```
 
 7. Generate training datasets via point-in-time join.
 
 ```sh
 oomcli join \
-	--feature account.state,account.credit_score,account.account_age_days,account.has_2fa_installed,transaction_stats.transaction_count_7d,transaction_stats.transaction_count_30d \
-	--input-file label.csv
+  --feature state,credit_score,account_age_days,has_2fa_installed,transaction_count_7d,transaction_count_30d \
+  --input-file label.csv
 ```
 
 ```text
-+------------+------------+---------------+----------------------+--------------------------+---------------------------+----------------------------------------+-----------------------------------------+
-| entity_key | unix_milli | account.state | account.credit_score | account.account_age_days | account.has_2fa_installed | transaction_stats.transaction_count_7d | transaction_stats.transaction_count_30d |
-+------------+------------+---------------+----------------------+--------------------------+---------------------------+----------------------------------------+-----------------------------------------+
-|       1002 | 1950236233 | Hawaii        |                  625 |                      861 | true                      |                                     11 |                                      36 |
-|       1003 | 1950411318 | Arkansas      |                  730 |                      958 | false                     |                                      0 |                                      16 |
-|       1004 | 1950653614 | Louisiana     |                  610 |                     1570 | false                     |                                     12 |                                      26 |
-|       1005 | 1950166137 | South Dakota  |                  635 |                     1953 | false                     |                                      7 |                                      30 |
-|       1006 | 1950403162 | Louisiana     |                  710 |                       32 | false                     |                                      8 |                                      22 |
-|       1007 | 1950160030 | New Mexico    |                  645 |                       37 | true                      |                                      5 |                                      40 |
-|       1008 | 1950274859 | Nevada        |                  735 |                     1627 | false                     |                                     12 |                                      51 |
-|       1009 | 1949958846 | Kentucky      |                  650 |                       88 | true                      |                                     11 |                                      23 |
-|       1010 | 1949920686 | Delaware      |                  680 |                     1687 | false                     |                                      2 |                                      39 |
-+------------+------------+---------------+----------------------+--------------------------+---------------------------+----------------------------------------+-----------------------------------------+
++------------+------------+--------------+--------------+------------------+-------------------+----------------------+-----------------------+
+| entity_key | unix_time  |    state     | credit_score | account_age_days | has_2fa_installed | transaction_count_7d | transaction_count_30d |
++------------+------------+--------------+--------------+------------------+-------------------+----------------------+-----------------------+
+|       1001 | 1950049136 | Arizona      |          685 |             1547 | false             |                    9 |                    41 |
+|       1002 | 1950236233 | Hawaii       |          625 |              861 | true              |                   11 |                    36 |
+|       1003 | 1950411318 | Arkansas     |          730 |              958 | false             |                    0 |                    16 |
+|       1004 | 1950653614 | Louisiana    |          610 |             1570 | false             |                   12 |                    26 |
+|       1005 | 1950166137 | South Dakota |          635 |             1953 | false             |                    7 |                    30 |
+|       1006 | 1950403162 | Louisiana    |          710 |               32 | false             |                    8 |                    22 |
+|       1007 | 1950160030 | New Mexico   |          645 |               37 | true              |                    5 |                    40 |
+|       1008 | 1950274859 | Nevada       |          735 |             1627 | false             |                   12 |                    51 |
+|       1009 | 1949958846 | Kentucky     |          650 |               88 | true              |                   11 |                    23 |
+|       1010 | 1949920686 | Delaware     |          680 |             1687 | false             |                    2 |                    39 |
++------------+------------+--------------+--------------+------------------+-------------------+----------------------+-----------------------+
 ```
 
 See [Quickstart](https://oom.ai/docs/quickstart) for more complete details.
 
 ## Roadmap
 
-See [Roadmap](https://oom.ai/docs/roadmap) for more details.
+We are looking to support stream features. See [Roadmap](https://oom.ai/docs/roadmap) for more details.
 
 ## Community
 
-Feel free to [join the community](https://oom.ai/slack) for questions and suggestions!
+Feel free to join our [Slack Community](https://oom.ai/slack) for questions and suggestions!
diff --git a/internal/database/database.go b/internal/database/database.go
index 4df26248..d6da9932 100644
--- a/internal/database/database.go
+++ b/internal/database/database.go
@@ -2,9 +2,9 @@ package database
 
 import (
 	"context"
+	"fmt"
 
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
-	"github.com/pkg/errors"
 
 	"github.com/oom-ai/oomstore/internal/database/metadata"
 	metadataMySQL "github.com/oom-ai/oomstore/internal/database/metadata/mysql"
@@ -48,7 +48,7 @@ func OpenOnlineStore(opt types.OnlineStoreConfig) (online.Store, error) {
 	case types.BackendTiKV:
 		return onlineTiKV.Open(opt.TiKV)
 	default:
-		return nil, errors.Errorf("unsupported backend: %s", opt.Backend)
+		return nil, fmt.Errorf("unsupported backend: %s", opt.Backend)
 	}
 }
 
@@ -63,7 +63,7 @@ func OpenMetadataStore(opt types.MetadataStoreConfig) (metadata.Store, error) {
 	case types.BackendSQLite:
 		return metadataSQLite.Open(context.Background(), opt.SQLite)
 	default:
-		return nil, errors.Errorf("unsupported backend: %s", opt.Backend)
+		return nil, fmt.Errorf("unsupported backend: %s", opt.Backend)
 	}
 }
 
@@ -78,7 +78,7 @@ func CreateMetadataDatabase(ctx context.Context, opt types.MetadataStoreConfig)
 	case types.BackendSQLite:
 		return metadataSQLite.CreateDatabase(ctx, opt.SQLite)
 	default:
-		return errors.Errorf("unsupported backend: %s", opt.Backend)
+		return fmt.Errorf("unsupported backend: %s", opt.Backend)
 	}
 }
 
@@ -99,6 +99,6 @@ func OpenOfflineStore(ctx context.Context, opt types.OfflineStoreConfig) (offlin
 	case types.BackendSQLite:
 		return offlineSQLite.Open(opt.SQLite)
 	default:
-		return nil, errors.Errorf("unsupported backend: %s", opt.Backend)
+		return nil, fmt.Errorf("unsupported backend: %s", opt.Backend)
 	}
 }
diff --git a/internal/database/dbutil/schema.go b/internal/database/dbutil/schema.go
index c03e8fe4..b23ae56c 100644
--- a/internal/database/dbutil/schema.go
+++ b/internal/database/dbutil/schema.go
@@ -57,11 +57,7 @@ func createTableDDL(tableName string, columns ColumnList, pkFields []string, bac
 			panic(fmt.Sprintf("unsupported backend type %s", backend))
 		}
 	}
-	tableName = qt(tableName)
-	if backend == types.BackendSnowflake {
-		tableName = fmt.Sprintf("PUBLIC.%s", tableName)
-	}
-	return fmt.Sprintf("CREATE TABLE %s (\n%s\n)", tableName, tableDef)
+	return fmt.Sprintf("CREATE TABLE %s (\n%s\n)", qt(tableName), tableDef)
 }
 
 func BuildIndexDDL(tableName string, indexName string, fields []string, backend types.BackendType) string {
diff --git a/internal/database/offline/sqlutil/join_helper.go b/internal/database/offline/sqlutil/join_helper.go
index 38f4c238..e70d6ba6 100644
--- a/internal/database/offline/sqlutil/join_helper.go
+++ b/internal/database/offline/sqlutil/join_helper.go
@@ -171,10 +171,6 @@ func prepareTableSchema(dbOpt dbutil.DBOpt, entity types.Entity, tableName strin
 		entityType = "VARCHAR(255)"
 		valueType = "TEXT"
 		qtTableName = qt(tableName)
-	case types.BackendSnowflake:
-		entityType = "TEXT"
-		valueType = "TEXT"
-		qtTableName = fmt.Sprintf("PUBLIC.%s", qt(tableName))
 	default:
 		entityType = "TEXT"
 		valueType = "TEXT"
diff --git a/oomagent/server.go b/oomagent/server.go
index 10e0764a..39d1361b 100644
--- a/oomagent/server.go
+++ b/oomagent/server.go
@@ -2,18 +2,17 @@ package main
 
 import (
 	"context"
+	"fmt"
 	"io"
 	"log"
 	"time"
 
-	"github.com/pkg/errors"
-	code "google.golang.org/genproto/googleapis/rpc/code"
-	status "google.golang.org/genproto/googleapis/rpc/status"
-	"google.golang.org/protobuf/types/known/structpb"
-
 	"github.com/oom-ai/oomstore/oomagent/codegen"
 	"github.com/oom-ai/oomstore/pkg/oomstore"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
+	code "google.golang.org/genproto/googleapis/rpc/code"
+	status "google.golang.org/genproto/googleapis/rpc/status"
+	"google.golang.org/protobuf/types/known/structpb"
 )
 
 type server struct {
@@ -258,7 +257,7 @@ func (s *server) ChannelJoin(stream codegen.OomAgent_ChannelJoinServer) error {
 			break
 		}
 		if req.GetEntityRow() == nil {
-			globalErr = errors.Errorf("cannot process nil entity row")
+			globalErr = fmt.Errorf("cannot process nil entity row")
 			break
 		}
 		entityRows <- types.EntityRow{
@@ -423,7 +422,7 @@ func convertInterfaceToValue(i interface{}) (*codegen.Value, error) {
 			},
 		}, nil
 	default:
-		return nil, errors.Errorf("unsupported value type %T", i)
+		return nil, fmt.Errorf("unsupported value type %T", i)
 	}
 }
 
@@ -432,7 +431,7 @@ func convertJoinedRow(row []interface{}) ([]*codegen.Value, error) {
 	for _, value := range row {
 		v, err := convertInterfaceToValue(value)
 		if err != nil {
-			return nil, errors.Errorf("failed to marshal %v", value)
+			return nil, fmt.Errorf("failed to marshal %v", value)
 		}
 		res = append(res, v)
 	}
diff --git a/oomcli/cmd/apply.go b/oomcli/cmd/apply.go
index 7cc3ffdd..336c051c 100644
--- a/oomcli/cmd/apply.go
+++ b/oomcli/cmd/apply.go
@@ -31,7 +31,7 @@ var applyCmd = &cobra.Command{
 		defer file.Close()
 
 		if err := oomStore.Apply(ctx, apply.ApplyOpt{R: file}); err != nil {
-			log.Fatalf("apply failed: %+v", err)
+			log.Fatalf("apply failed: %v", err)
 		}
 
 		log.Println("applied")
diff --git a/oomcli/cmd/edit.go b/oomcli/cmd/edit.go
index c57da384..c266f54a 100644
--- a/oomcli/cmd/edit.go
+++ b/oomcli/cmd/edit.go
@@ -6,7 +6,6 @@ import (
 	"os"
 	"os/exec"
 
-	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	"github.com/oom-ai/oomstore/pkg/oomstore"
@@ -44,7 +43,7 @@ func checkCommandExist(cmd string) bool {
 
 func editFileByExternalEditor(ctx context.Context, fileName string) error {
 	if !checkCommandExist(editor) {
-		return errors.Errorf("%s not found", editor)
+		return fmt.Errorf("%s not found", editor)
 	}
 
 	cmd := exec.CommandContext(ctx, editor, fileName)
diff --git a/oomcli/cmd/edit_entity.go b/oomcli/cmd/edit_entity.go
index 869ab64c..fb98f40d 100644
--- a/oomcli/cmd/edit_entity.go
+++ b/oomcli/cmd/edit_entity.go
@@ -42,7 +42,7 @@ var editEntityCmd = &cobra.Command{
 		}
 
 		if err = edit(ctx, oomStore, fileName); err != nil {
-			log.Fatalf("apply failed: %+v", err)
+			log.Fatalf("apply failed: %v", err)
 		}
 		log.Println("applied")
 	},
diff --git a/oomcli/cmd/edit_feature.go b/oomcli/cmd/edit_feature.go
index 5321c4fa..154bd7e4 100644
--- a/oomcli/cmd/edit_feature.go
+++ b/oomcli/cmd/edit_feature.go
@@ -49,7 +49,7 @@ var editFeatureCmd = &cobra.Command{
 		}
 
 		if err = edit(ctx, oomStore, fileName); err != nil {
-			log.Fatalf("apply failed: %+v", err)
+			log.Fatalf("apply failed: %v", err)
 		}
 		log.Println("applied")
 	},
diff --git a/oomcli/cmd/edit_group.go b/oomcli/cmd/edit_group.go
index e776bcbd..266c8a33 100644
--- a/oomcli/cmd/edit_group.go
+++ b/oomcli/cmd/edit_group.go
@@ -47,7 +47,7 @@ var editGroupCmd = &cobra.Command{
 		}
 
 		if err = edit(ctx, oomStore, fileName); err != nil {
-			log.Fatalf("apply failed: %+v", err)
+			log.Fatalf("apply failed: %v", err)
 		}
 		log.Println("applied")
 	},
diff --git a/oomcli/cmd/export.go b/oomcli/cmd/export.go
index 3440a01a..afc7be45 100644
--- a/oomcli/cmd/export.go
+++ b/oomcli/cmd/export.go
@@ -25,7 +25,7 @@ var exportCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if err := export(ctx, oomStore, exportOpt, *exportOutput); err != nil {
-			log.Fatalf("failed exporting features: %+v\n", err)
+			log.Fatalf("failed exporting features: %v\n", err)
 		}
 	},
 }
diff --git a/oomcli/cmd/export_helper.go b/oomcli/cmd/export_helper.go
index 05abac42..2a69458c 100644
--- a/oomcli/cmd/export_helper.go
+++ b/oomcli/cmd/export_helper.go
@@ -7,11 +7,9 @@ import (
 	"os"
 
 	"github.com/olekukonko/tablewriter"
-	"github.com/pkg/errors"
-	"github.com/spf13/cast"
-
 	"github.com/oom-ai/oomstore/pkg/oomstore"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
+	"github.com/spf13/cast"
 )
 
 func export(ctx context.Context, store *oomstore.OomStore, opt types.ChannelExportOpt, output string) error {
@@ -32,7 +30,7 @@ func printExportResult(exportResult *types.ExportResult, output string) error {
 	case ASCIITable:
 		return printExportResultInASCIITable(exportResult)
 	default:
-		return errors.Errorf("unsupported output format %s", output)
+		return fmt.Errorf("unsupported output format %s", output)
 	}
 }
 
diff --git a/oomcli/cmd/get_meta_entity.go b/oomcli/cmd/get_meta_entity.go
index de6d9d58..d3e97101 100644
--- a/oomcli/cmd/get_meta_entity.go
+++ b/oomcli/cmd/get_meta_entity.go
@@ -6,11 +6,10 @@ import (
 	"log"
 	"os"
 
-	"github.com/spf13/cobra"
-
 	"github.com/oom-ai/oomstore/pkg/oomstore"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types/apply"
+	"github.com/spf13/cobra"
 )
 
 type getMetaEntityOption struct {
@@ -40,7 +39,7 @@ var getMetaEntityCmd = &cobra.Command{
 		}
 
 		if err = serializeEntitiesToWriter(ctx, os.Stdout, oomStore, entities, *getMetaOutput); err != nil {
-			log.Fatalf("failed printing entities, error: %+v\n", err)
+			log.Fatalf("failed printing entities, error: %v\n", err)
 		}
 	},
 }
diff --git a/oomcli/cmd/get_meta_feature.go b/oomcli/cmd/get_meta_feature.go
index 8fae6f9c..2d37c89b 100644
--- a/oomcli/cmd/get_meta_feature.go
+++ b/oomcli/cmd/get_meta_feature.go
@@ -7,7 +7,6 @@ import (
 	"log"
 	"os"
 
-	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	"github.com/oom-ai/oomstore/pkg/oomstore"
@@ -43,7 +42,7 @@ var getMetaFeatureCmd = &cobra.Command{
 		}
 
 		if err := serializeFeatureToWriter(os.Stdout, features, *getMetaOutput); err != nil {
-			log.Fatalf("failed printing features: %+v\n", err)
+			log.Fatalf("failed printing features: %v\n", err)
 		}
 	},
 }
@@ -63,7 +62,7 @@ func queryFeatures(ctx context.Context, oomStore *oomstore.OomStore, opt types.L
 	}
 
 	if opt.FeatureFullNames != nil && len(features) == 0 {
-		return nil, errors.Errorf("feature '%s' not found", (*opt.FeatureFullNames)[0])
+		return nil, fmt.Errorf("feature '%s' not found", (*opt.FeatureFullNames)[0])
 	}
 
 	return features, nil
diff --git a/oomcli/cmd/get_meta_group.go b/oomcli/cmd/get_meta_group.go
index cc5a7c79..457fe634 100644
--- a/oomcli/cmd/get_meta_group.go
+++ b/oomcli/cmd/get_meta_group.go
@@ -9,7 +9,6 @@ import (
 
 	"github.com/oom-ai/oomstore/pkg/oomstore"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
-	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 )
 
@@ -41,11 +40,11 @@ var getMetaGroupCmd = &cobra.Command{
 
 		groups, err := queryGroups(ctx, oomStore, getMetaGroupOpt.entityName, getMetaGroupOpt.groupName)
 		if err != nil {
-			log.Fatalf("%+v", err)
+			log.Fatal(err)
 		}
 
 		if err = serializeGroupToWriter(ctx, os.Stdout, oomStore, groups, *getMetaOutput); err != nil {
-			log.Fatalf("%+v", err)
+			log.Fatal(err)
 		}
 	},
 }
@@ -68,7 +67,7 @@ func queryGroups(ctx context.Context, oomStore *oomstore.OomStore, entityName, g
 		}
 
 		if entityName != nil && group.Entity.Name != *entityName {
-			return nil, errors.Errorf("group '%s' entityName is '%s' not '%s'", *groupName, group.Entity.Name, *entityName)
+			return nil, fmt.Errorf("group '%s' entityName is '%s' not '%s'", *groupName, group.Entity.Name, *entityName)
 		}
 		return types.GroupList{group}, err
 	}
diff --git a/oomcli/cmd/get_meta_revision.go b/oomcli/cmd/get_meta_revision.go
index a821de64..34cff59d 100644
--- a/oomcli/cmd/get_meta_revision.go
+++ b/oomcli/cmd/get_meta_revision.go
@@ -38,14 +38,14 @@ var getMetaRevisionCmd = &cobra.Command{
 		if getRevisionOpt.groupName != nil {
 			group, err := oomStore.GetGroupByName(ctx, *getRevisionOpt.groupName)
 			if err != nil {
-				log.Fatalf("failed to get feature group name=%s: %+v", *getRevisionOpt.groupName, err)
+				log.Fatalf("failed to get feature group name=%s: %v", *getRevisionOpt.groupName, err)
 			}
 			groupID = &group.ID
 		}
 
 		revisions, err := oomStore.ListRevision(ctx, groupID)
 		if err != nil {
-			log.Fatalf("failed geting revisions, error %+v\n", err)
+			log.Fatalf("failed geting revisions, error %v\n", err)
 		}
 
 		if len(args) > 0 {
@@ -57,7 +57,7 @@ var getMetaRevisionCmd = &cobra.Command{
 		}
 
 		if err := serializeMetadata(os.Stdout, revisions, *getMetaOutput, *getMetaWide); err != nil {
-			log.Fatalf("failed printing entities, error %+v\n", err)
+			log.Fatalf("failed printing entities, error %v\n", err)
 		}
 	},
 }
diff --git a/oomcli/cmd/get_online.go b/oomcli/cmd/get_online.go
index 0670c486..6ee42cd0 100644
--- a/oomcli/cmd/get_online.go
+++ b/oomcli/cmd/get_online.go
@@ -3,11 +3,11 @@ package cmd
 import (
 	"context"
 	"encoding/csv"
+	"fmt"
 	"log"
 	"os"
 
 	"github.com/olekukonko/tablewriter"
-	"github.com/pkg/errors"
 	"github.com/spf13/cast"
 	"github.com/spf13/cobra"
 
@@ -26,11 +26,11 @@ var getOnlineCmd = &cobra.Command{
 
 		featureValues, err := oomStore.OnlineGet(ctx, onlineGetOpt)
 		if err != nil {
-			log.Fatalf("failed getting online features: %+v", err)
+			log.Fatalf("failed getting online features: %v", err)
 		}
 
 		if err := printOnlineFeatures(featureValues, *getOutput); err != nil {
-			log.Fatalf("failed printing online feature values, error %+v\n", err)
+			log.Fatalf("failed printing online feature values, error %v\n", err)
 		}
 	},
 }
@@ -54,7 +54,7 @@ func printOnlineFeatures(featureValues *types.FeatureValues, output string) erro
 	case ASCIITable:
 		return printOnlineFeaturesInASCIITable(featureValues)
 	default:
-		return errors.Errorf("unsupported output format %s", output)
+		return fmt.Errorf("unsupported output format %s", output)
 	}
 }
 
diff --git a/oomcli/cmd/import.go b/oomcli/cmd/import.go
index 0e1e4e9d..775f19ed 100644
--- a/oomcli/cmd/import.go
+++ b/oomcli/cmd/import.go
@@ -41,7 +41,7 @@ var importCmd = &cobra.Command{
 		log.Println("importing features ...")
 		revisionID, err := oomStore.Import(ctx, importOpt)
 		if err != nil {
-			log.Fatalf("failed importing features: %+v\n", err)
+			log.Fatalf("failed importing features: %v\n", err)
 		}
 		log.Println("succeeded")
 		fmt.Printf("RevisionID: %d\n", revisionID)
diff --git a/oomcli/cmd/join.go b/oomcli/cmd/join.go
index 33ae0382..02b7374c 100644
--- a/oomcli/cmd/join.go
+++ b/oomcli/cmd/join.go
@@ -24,7 +24,7 @@ var joinCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if err := join(ctx, oomStore, joinOpt, *joinOutput); err != nil {
-			log.Fatalf("failed joining historical features: %+v\n", err)
+			log.Fatalf("failed joining historical features: %v\n", err)
 		}
 	},
 }
diff --git a/oomcli/cmd/join_helper.go b/oomcli/cmd/join_helper.go
index be3362eb..2df91d94 100644
--- a/oomcli/cmd/join_helper.go
+++ b/oomcli/cmd/join_helper.go
@@ -3,14 +3,13 @@ package cmd
 import (
 	"context"
 	"encoding/csv"
+	"fmt"
 	"os"
 
-	"github.com/pkg/errors"
-	"github.com/spf13/cast"
-
 	"github.com/olekukonko/tablewriter"
 	"github.com/oom-ai/oomstore/pkg/oomstore"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
+	"github.com/spf13/cast"
 )
 
 type JoinOpt struct {
@@ -47,7 +46,7 @@ func printJoinResult(joinResult *types.JoinResult, output string) error {
 	case ASCIITable:
 		return printJoinResultInASCIITable(joinResult)
 	default:
-		return errors.Errorf("unsupported output format %s", output)
+		return fmt.Errorf("unsupported output format %s", output)
 	}
 }
 
diff --git a/oomcli/cmd/register_entity.go b/oomcli/cmd/register_entity.go
index 94c1f197..24da9ba0 100644
--- a/oomcli/cmd/register_entity.go
+++ b/oomcli/cmd/register_entity.go
@@ -23,7 +23,7 @@ var registerEntityCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if _, err := oomStore.CreateEntity(ctx, registerEntityOpt); err != nil {
-			log.Fatalf("failed registering new entity: %+v\n", err)
+			log.Fatalf("failed registering new entity: %v\n", err)
 		}
 	},
 }
diff --git a/oomcli/cmd/register_feature.go b/oomcli/cmd/register_feature.go
index 1b363497..bd817c45 100644
--- a/oomcli/cmd/register_feature.go
+++ b/oomcli/cmd/register_feature.go
@@ -29,7 +29,7 @@ var registerBatchFeatureCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if _, err := oomStore.CreateFeature(ctx, registerBatchFeatureOpt); err != nil {
-			log.Fatalf("failed registering new feature: %+v\n", err)
+			log.Fatalf("failed registering new feature: %v\n", err)
 		}
 	},
 }
diff --git a/oomcli/cmd/register_group.go b/oomcli/cmd/register_group.go
index 22e4b88b..90269a45 100644
--- a/oomcli/cmd/register_group.go
+++ b/oomcli/cmd/register_group.go
@@ -27,7 +27,7 @@ var registerGroupCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if _, err := oomStore.CreateGroup(ctx, registerGroupOpt); err != nil {
-			log.Fatalf("failed registering new group: %+v\n", err)
+			log.Fatalf("failed registering new group: %v\n", err)
 		}
 	},
 }
diff --git a/oomcli/cmd/serialize.go b/oomcli/cmd/serialize.go
index 2c368320..2fa9780a 100644
--- a/oomcli/cmd/serialize.go
+++ b/oomcli/cmd/serialize.go
@@ -2,6 +2,7 @@ package cmd
 
 import (
 	"encoding/csv"
+	"fmt"
 	"io"
 	"os"
 	"reflect"
@@ -9,7 +10,6 @@ import (
 
 	"github.com/fatih/structtag"
 	"github.com/olekukonko/tablewriter"
-	"github.com/pkg/errors"
 	"github.com/spf13/cast"
 	"gopkg.in/yaml.v3"
 )
@@ -109,7 +109,7 @@ func serializeMetadata(w io.Writer, i interface{}, format string, wide bool) err
 	case Column:
 		return serializeInASCIITable(w, header, records, false)
 	default:
-		return errors.Errorf("unsupported output format %s", format)
+		return fmt.Errorf("unsupported output format %s", format)
 	}
 }
 
diff --git a/oomcli/cmd/snapshot.go b/oomcli/cmd/snapshot.go
index 9991c3d3..f1c4db67 100644
--- a/oomcli/cmd/snapshot.go
+++ b/oomcli/cmd/snapshot.go
@@ -23,7 +23,7 @@ var snapshotCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if err := oomStore.Snapshot(ctx, snapshotGroupName); err != nil {
-			log.Fatalf("failed to take snapshot for the group %s: %+v\n", snapshotGroupName, err)
+			log.Fatalf("failed to take snapshot for the group %s: %v\n", snapshotGroupName, err)
 		}
 	},
 }
diff --git a/oomcli/cmd/sync.go b/oomcli/cmd/sync.go
index 118432e1..3cadb48d 100644
--- a/oomcli/cmd/sync.go
+++ b/oomcli/cmd/sync.go
@@ -20,7 +20,7 @@ var syncCmd = &cobra.Command{
 
 		log.Println("syncing features ...")
 		if err := oomStore.Sync(ctx, syncOpt); err != nil {
-			log.Fatalf("failed sync features: %+v\n", err)
+			log.Fatalf("failed sync features: %v\n", err)
 		}
 		log.Println("succeeded.")
 	},
diff --git a/oomcli/cmd/types.go b/oomcli/cmd/types.go
index b53e82bd..d46438e0 100644
--- a/oomcli/cmd/types.go
+++ b/oomcli/cmd/types.go
@@ -1,10 +1,10 @@
 package cmd
 
 import (
+	"fmt"
 	"time"
 
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
-	"github.com/pkg/errors"
 )
 
 type FlattenEntity struct {
@@ -131,7 +131,7 @@ func parseTokenLists(i interface{}) (headerTokens TokenList, dataTokens []TokenL
 			dataTokens = append(dataTokens, tokens)
 		}
 	default:
-		return nil, nil, errors.Errorf("unsupported type %T", i)
+		return nil, nil, fmt.Errorf("unsupported type %T", i)
 	}
 	headerTokens, err = parseTokens(element)
 	if err != nil {
diff --git a/oomcli/cmd/update_entity.go b/oomcli/cmd/update_entity.go
index 93d4fa83..fc2f8ca7 100644
--- a/oomcli/cmd/update_entity.go
+++ b/oomcli/cmd/update_entity.go
@@ -26,7 +26,7 @@ var updateEntityCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if err := oomStore.UpdateEntity(ctx, updateEntityOpt); err != nil {
-			log.Fatalf("failed to update entity id=%s, err %+v\n", updateEntityOpt.EntityName, err)
+			log.Fatalf("failed to update entity id=%s, err %v\n", updateEntityOpt.EntityName, err)
 		}
 	},
 }
diff --git a/oomcli/cmd/update_feature.go b/oomcli/cmd/update_feature.go
index 0ecb677c..b83d3ade 100644
--- a/oomcli/cmd/update_feature.go
+++ b/oomcli/cmd/update_feature.go
@@ -26,7 +26,7 @@ var updateFeatureCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if err := oomStore.UpdateFeature(ctx, updateFeatureOpt); err != nil {
-			log.Fatalf("failed to update feature %s, err %+v\n", updateFeatureOpt.FeatureFullName, err)
+			log.Fatalf("failed to update feature %s, err %v\n", updateFeatureOpt.FeatureFullName, err)
 		}
 	},
 }
diff --git a/oomcli/cmd/update_group.go b/oomcli/cmd/update_group.go
index cd30cd22..7501b0cd 100644
--- a/oomcli/cmd/update_group.go
+++ b/oomcli/cmd/update_group.go
@@ -26,7 +26,7 @@ var updateGroupCmd = &cobra.Command{
 		defer oomStore.Close()
 
 		if err := oomStore.UpdateGroup(ctx, updateGroupOpt); err != nil {
-			log.Fatalf("failed updating group %s, err %+v\n", updateGroupOpt.GroupName, err)
+			log.Fatalf("failed updating group %s, err %v\n", updateGroupOpt.GroupName, err)
 		}
 	},
 }
diff --git a/oomcli/cmd/util.go b/oomcli/cmd/util.go
index be01b89f..7f27e2b4 100644
--- a/oomcli/cmd/util.go
+++ b/oomcli/cmd/util.go
@@ -23,7 +23,7 @@ const (
 func mustOpenOomStore(ctx context.Context, opt types.OomStoreConfig) *oomstore.OomStore {
 	store, err := oomstore.Open(ctx, oomStoreCfg)
 	if err != nil {
-		log.Fatalf("failed opening OomStore: %+v", err)
+		log.Fatalf("failed opening OomStore: %v", err)
 	}
 	return store
 }
diff --git a/pkg/oomstore/apply.go b/pkg/oomstore/apply.go
index d5e6ecf9..1be400bd 100644
--- a/pkg/oomstore/apply.go
+++ b/pkg/oomstore/apply.go
@@ -6,7 +6,6 @@ import (
 	"io"
 
 	"github.com/mitchellh/mapstructure"
-	"github.com/pkg/errors"
 	"github.com/spf13/cast"
 	"gopkg.in/yaml.v3"
 
@@ -275,7 +274,7 @@ func buildApplyStage(ctx context.Context, opt apply.ApplyOpt) (*apply.ApplyStage
 				}
 			}
 		default:
-			return nil, errors.Errorf("invalid kind '%s'", kind)
+			return nil, fmt.Errorf("invalid kind '%s'", kind)
 		}
 	}
 	return stage, nil
@@ -288,7 +287,7 @@ func parseKind(data map[string]interface{}) (string, error) {
 	if _, ok := data["items"]; ok {
 		return "Items", nil
 	}
-	return "", errors.Errorf("invalid yaml: missing kind or items")
+	return "", fmt.Errorf("invalid yaml: missing kind or items")
 }
 
 func parseItemsKind(data map[string]interface{}) (string, error) {
diff --git a/pkg/oomstore/export.go b/pkg/oomstore/export.go
index 3d99a0cc..333a207a 100644
--- a/pkg/oomstore/export.go
+++ b/pkg/oomstore/export.go
@@ -6,11 +6,9 @@ import (
 	"fmt"
 	"os"
 
-	"github.com/pkg/errors"
-	"github.com/spf13/cast"
-
 	"github.com/oom-ai/oomstore/internal/database/offline"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
+	"github.com/spf13/cast"
 )
 
 /*
@@ -52,7 +50,7 @@ func (s *OomStore) ChannelExport(ctx context.Context, opt types.ChannelExportOpt
 
 	entity := revision.Group.Entity
 	if entity == nil {
-		return nil, errors.Errorf("failed to get entity id=%d", revision.GroupID)
+		return nil, fmt.Errorf("failed to get entity id=%d", revision.GroupID)
 	}
 
 	stream, exportErr := s.offline.Export(ctx, offline.ExportOpt{
diff --git a/pkg/oomstore/feature.go b/pkg/oomstore/feature.go
index bf86b374..6ababd11 100644
--- a/pkg/oomstore/feature.go
+++ b/pkg/oomstore/feature.go
@@ -5,8 +5,6 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/pkg/errors"
-
 	"github.com/oom-ai/oomstore/internal/database/metadata"
 	"github.com/oom-ai/oomstore/internal/database/online"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
@@ -107,7 +105,7 @@ func validateFeatureFullNames(names []string) error {
 	for _, name := range names {
 		nameSlice := strings.Split(name, FeatureFullNameSeparator)
 		if len(nameSlice) != 2 {
-			return errors.Errorf("invalid feature full name %s", name)
+			return fmt.Errorf("invalid feature full name %s", name)
 		}
 	}
 	return nil
diff --git a/pkg/oomstore/import.go b/pkg/oomstore/import.go
index e9702533..1d35787b 100644
--- a/pkg/oomstore/import.go
+++ b/pkg/oomstore/import.go
@@ -3,10 +3,10 @@ package oomstore
 import (
 	"bufio"
 	"context"
+	"fmt"
 	"os"
 	"time"
 
-	"github.com/pkg/errors"
 	"github.com/spf13/cast"
 
 	"github.com/oom-ai/oomstore/internal/database/dbutil"
@@ -39,7 +39,7 @@ func (s *OomStore) Import(ctx context.Context, opt types.ImportOpt) (int, error)
 	case types.TABLE_LINK:
 		return s.tableLinkImport(ctx, importOpt, opt.TableLinkDataSource)
 	default:
-		return 0, errors.Errorf("unsupported data source: %v", opt.DataSourceType)
+		return 0, fmt.Errorf("unsupported data source: %v", opt.DataSourceType)
 	}
 }
 
@@ -52,11 +52,11 @@ func (s *OomStore) csvReaderImport(ctx context.Context, opt *importOpt, dataSour
 		return 0, err
 	}
 	if hasDup(cast.ToStringSlice(header)) {
-		return 0, errors.Errorf("csv data source has duplicated columns: %v", header)
+		return 0, fmt.Errorf("csv data source has duplicated columns: %v", header)
 	}
 	columnNames := append([]string{opt.entity.Name}, opt.features.Names()...)
 	if !stringSliceEqual(cast.ToStringSlice(header), columnNames) {
-		return 0, errors.Errorf("csv header of the data source %v doesn't match the feature group schema %v", header, columnNames)
+		return 0, fmt.Errorf("csv header of the data source %v doesn't match the feature group schema %v", header, columnNames)
 	}
 
 	newRevisionID, snapshotTableName, err := s.metadata.CreateRevision(ctx, metadata.CreateRevisionOpt{
@@ -110,12 +110,12 @@ func (s *OomStore) tableLinkImport(ctx context.Context, opt *importOpt, dataSour
 		for _, field := range tableSchema.Fields {
 			if field.Name == f.Name {
 				if field.ValueType != f.ValueType {
-					return errors.Errorf("expect value type '%s', got '%s'", f.ValueType, field.ValueType)
+					return fmt.Errorf("expect value type '%s', got '%s'", f.ValueType, field.ValueType)
 				}
 				return nil
 			}
 		}
-		return errors.Errorf("field '%s' found in target table", f.Name)
+		return fmt.Errorf("field '%s' found in target table", f.Name)
 	}
 	for _, feature := range opt.features {
 		if err := validate(feature); err != nil {
@@ -187,13 +187,13 @@ func (s *OomStore) parseImportOpt(ctx context.Context, opt types.ImportOpt) (*im
 		return nil, err
 	}
 	if features == nil {
-		err = errors.Errorf("no features under group: %s", opt.GroupName)
+		err = fmt.Errorf("no features under group: %s", opt.GroupName)
 		return nil, err
 	}
 
 	entity := group.Entity
 	if entity == nil {
-		return nil, errors.Errorf("no entity found by group: %s", opt.GroupName)
+		return nil, fmt.Errorf("no entity found by group: %s", opt.GroupName)
 	}
 
 	return &importOpt{
diff --git a/pkg/oomstore/join.go b/pkg/oomstore/join.go
index 9d761d06..19ec6dc3 100644
--- a/pkg/oomstore/join.go
+++ b/pkg/oomstore/join.go
@@ -3,6 +3,7 @@ package oomstore
 import (
 	"context"
 	"encoding/csv"
+	"fmt"
 	"io"
 	"math"
 	"os"
@@ -12,7 +13,6 @@ import (
 	"github.com/oom-ai/oomstore/internal/database/metadata"
 	"github.com/oom-ai/oomstore/internal/database/offline"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
-	"github.com/pkg/errors"
 	"github.com/spf13/cast"
 )
 
@@ -46,7 +46,7 @@ func (s *OomStore) ChannelJoin(ctx context.Context, opt types.ChannelJoinOpt) (*
 		return nil, err
 	}
 	if entity == nil {
-		return nil, errors.Errorf("failed to get shared entity")
+		return nil, fmt.Errorf("failed to get shared entity")
 	}
 
 	featureMap := buildGroupToFeaturesMap(features)
@@ -164,7 +164,7 @@ func GetEntityRowsFromInputFile(inputFilePath string) (<-chan types.EntityRow, [
 				return
 			}
 			if len(line) < 2 {
-				readErr = errors.Errorf("at least 2 values per row, got %d value(s) at row %d", len(line), i)
+				readErr = fmt.Errorf("at least 2 values per row, got %d value(s) at row %d", len(line), i)
 				return
 			}
 			unixMilli, err := strconv.Atoi(line[1])
diff --git a/pkg/oomstore/online_query.go b/pkg/oomstore/online_query.go
index a3f89844..6bd60fac 100644
--- a/pkg/oomstore/online_query.go
+++ b/pkg/oomstore/online_query.go
@@ -2,8 +2,7 @@ package oomstore
 
 import (
 	"context"
-
-	"github.com/pkg/errors"
+	"fmt"
 
 	"github.com/oom-ai/oomstore/internal/database/dbutil"
 	"github.com/oom-ai/oomstore/internal/database/metadata"
@@ -77,7 +76,7 @@ func (s *OomStore) OnlineMultiGet(ctx context.Context, opt types.OnlineMultiGetO
 		return nil, err
 	}
 	if entity == nil {
-		return nil, errors.Errorf("failed to get shared entity")
+		return nil, fmt.Errorf("failed to get shared entity")
 	}
 	featureMap := groupFeaturesByGroupID(features)
 
@@ -148,11 +147,11 @@ func getSharedEntity(features types.FeatureList) (*types.Entity, error) {
 		m[f.Group.EntityID] = f.Group.Entity
 	}
 	if len(m) != 1 {
-		return nil, errors.Errorf("expected 1 entity, got %d entities", len(m))
+		return nil, fmt.Errorf("expected 1 entity, got %d entities", len(m))
 	}
 
 	for _, entity := range m {
 		return entity, nil
 	}
-	return nil, errors.Errorf("expected 1 entity, got 0")
+	return nil, fmt.Errorf("expected 1 entity, got 0")
 }
diff --git a/pkg/oomstore/push.go b/pkg/oomstore/push.go
index cb473995..d44f2a2e 100644
--- a/pkg/oomstore/push.go
+++ b/pkg/oomstore/push.go
@@ -2,11 +2,11 @@ package oomstore
 
 import (
 	"context"
+	"fmt"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/oom-ai/oomstore/internal/database/online"
+
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
 )
 
@@ -21,7 +21,7 @@ func (s *OomStore) Push(ctx context.Context, opt types.PushOpt) error {
 	entity := features[0].Entity()
 	group := features[0].Group
 	if !stringSliceEqual(features.Names(), opt.FeatureNames) {
-		return errors.Errorf("FeatureNames %v does not match with group's features %v", opt.FeatureNames, features.Names())
+		return fmt.Errorf("FeatureNames %v does not match with group's features %v", opt.FeatureNames, features.Names())
 	}
 	values := make([]interface{}, 0, len(features))
 	for _, f := range features {
diff --git a/pkg/oomstore/sync.go b/pkg/oomstore/sync.go
index 51303d99..a69844ac 100644
--- a/pkg/oomstore/sync.go
+++ b/pkg/oomstore/sync.go
@@ -5,8 +5,6 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/oom-ai/oomstore/internal/database/metadata"
 	"github.com/oom-ai/oomstore/internal/database/offline"
 	"github.com/oom-ai/oomstore/internal/database/online"
@@ -19,7 +17,7 @@ import (
 // where size of the particular revision outgrows memory limit of your machine.
 func (s *OomStore) Sync(ctx context.Context, opt types.SyncOpt) error {
 	if err := s.metadata.Refresh(); err != nil {
-		return fmt.Errorf("failed to refresh informer, err=%v", err)
+		return fmt.Errorf("failed to refresh informer, err=%+v", err)
 	}
 	revision, err := s.GetRevision(ctx, opt.RevisionID)
 	if err != nil {
@@ -29,7 +27,7 @@ func (s *OomStore) Sync(ctx context.Context, opt types.SyncOpt) error {
 	group := revision.Group
 	prevOnlineRevisionID := group.OnlineRevisionID
 	if prevOnlineRevisionID != nil && *prevOnlineRevisionID == opt.RevisionID {
-		return errors.Errorf("the specific revision was synced to the online store, won't do it again this time")
+		return fmt.Errorf("the specific revision was synced to the online store, won't do it again this time")
 	}
 
 	features, err := s.ListFeature(ctx, types.ListFeatureOpt{
diff --git a/pkg/oomstore/types/apply/apply.go b/pkg/oomstore/types/apply/apply.go
index 56545cfa..16637c34 100644
--- a/pkg/oomstore/types/apply/apply.go
+++ b/pkg/oomstore/types/apply/apply.go
@@ -1,10 +1,9 @@
 package apply
 
 import (
+	"fmt"
 	"io"
 
-	"github.com/pkg/errors"
-
 	"github.com/oom-ai/oomstore/pkg/errdefs"
 	"github.com/oom-ai/oomstore/pkg/oomstore/types"
 )
@@ -37,10 +36,10 @@ type Feature struct {
 
 func (f *Feature) Validate() error {
 	if f.Name == "" {
-		return errdefs.InvalidAttribute(errors.Errorf("the name of feature should not be empty"))
+		return errdefs.InvalidAttribute(fmt.Errorf("the name of feature should not be empty"))
 	}
 	if f.ValueType == "" {
-		return errdefs.InvalidAttribute(errors.Errorf("the value type of feature should not be empty"))
+		return errdefs.InvalidAttribute(fmt.Errorf("the value type of feature should not be empty"))
 	}
 	return nil
 }
@@ -129,7 +128,7 @@ func FromGroupList(groups types.GroupList, features types.FeatureList) *GroupIte
 
 func (g *Group) Validate() error {
 	if g.Name == "" {
-		return errdefs.InvalidAttribute(errors.Errorf("the name of group should not be empty"))
+		return errdefs.InvalidAttribute(fmt.Errorf("the name of group should not be empty"))
 	}
 	return nil
 }
@@ -144,7 +143,7 @@ type Entity struct {
 
 func (e *Entity) Validate() error {
 	if e.Name == "" {
-		return errdefs.InvalidAttribute(errors.Errorf("the name of entity should not be empty"))
+		return errdefs.InvalidAttribute(fmt.Errorf("the name of entity should not be empty"))
 	}
 	return nil
 }
diff --git a/pkg/oomstore/types/config.go b/pkg/oomstore/types/config.go
index 1ec36785..016c7898 100644
--- a/pkg/oomstore/types/config.go
+++ b/pkg/oomstore/types/config.go
@@ -1,9 +1,8 @@
 package types
 
 import (
+	"fmt"
 	"time"
-
-	"github.com/pkg/errors"
 )
 
 type BackendType string
@@ -154,7 +153,7 @@ func (cfg *MetadataStoreConfig) Validate() error {
 		n++
 	}
 	if n != 1 {
-		return errors.Errorf("require exactly one metadata store backend")
+		return fmt.Errorf("require exactly one metadata store backend")
 	}
 	return nil
 }
@@ -194,7 +193,7 @@ func (cfg *OnlineStoreConfig) Validate() error {
 		n++
 	}
 	if n != 1 {
-		return errors.Errorf("require exactly one online store backend")
+		return fmt.Errorf("require exactly one online store backend")
 	}
 	return nil
 }
@@ -230,7 +229,7 @@ func (cfg *OfflineStoreConfig) Validate() error {
 		n++
 	}
 	if n != 1 {
-		return errors.Errorf("require exactly one offline store backend")
+		return fmt.Errorf("require exactly one offline store backend")
 	}
 	return nil
 }
diff --git a/scripts/config_source.yaml b/scripts/config_source.yaml
index b53755c7..30d224d8 100644
--- a/scripts/config_source.yaml
+++ b/scripts/config_source.yaml
@@ -24,8 +24,13 @@ tidb:
   password: oomplay
   database: oomplay
 
+tikv:
+  pd-addrs:
+    - 127.0.0.1:22379
+
 cassandra:
-  hosts: ['127.0.0.1:29042']
+  hosts:
+    - 127.0.0.1:29042
   user: oomplay
   password: oomplay
   keyspace: oomplay


Test patch:
diff --git a/internal/database/online/cassandra/store_test.go b/internal/database/online/cassandra/store_test.go
index 4fdc04a4..a9b6ac18 100644
--- a/internal/database/online/cassandra/store_test.go
+++ b/internal/database/online/cassandra/store_test.go
@@ -55,22 +55,27 @@ func TestOpen(t *testing.T) {
 }
 
 func TestGetExisted(t *testing.T) {
+	t.Skipf("Skip this test until we separate snapshot schema and cdc schema")
 	test_impl.TestGetExisted(t, prepareStore, destroyStore(KEYSPACE))
 }
 
 func TestGetNotExistedEntityKey(t *testing.T) {
+	t.Skipf("Skip this test until we separate snapshot schema and cdc schema")
 	test_impl.TestGetNotExistedEntityKey(t, prepareStore, destroyStore(KEYSPACE))
 }
 
 func TestMultiGet(t *testing.T) {
+	t.Skipf("Skip this test until we separate snapshot schema and cdc schema")
 	test_impl.TestMultiGet(t, prepareStore, destroyStore(KEYSPACE))
 }
 
 func TestPurgeRemovesSpecifiedRevision(t *testing.T) {
+	t.Skipf("Skip this test until we separate snapshot schema and cdc schema")
 	test_impl.TestPurgeRemovesSpecifiedRevision(t, prepareStore, destroyStore(KEYSPACE))
 }
 
 func TestPurgeNotRemovesOtherRevisions(t *testing.T) {
+	t.Skipf("Skip this test until we separate snapshot schema and cdc schema")
 	test_impl.TestPurgeNotRemovesOtherRevisions(t, prepareStore, destroyStore(KEYSPACE))
 }
 
diff --git a/oomcli/test/test_export.sh b/oomcli/test/test_export.sh
index 4ca016d1..6258b017 100755
--- a/oomcli/test/test_export.sh
+++ b/oomcli/test/test_export.sh
@@ -19,4 +19,15 @@ expected='device,price
 9,4500
 '
 actual=$(oomcli export --feature price --revision-id 1 -o csv)
-assert_eq "$case" "$(sort <<< "$expected")" "$(sort <<< "$actual")"
+assert_eq "$case" "$expected" "$actual"
+
+case='get with limit'
+expected='device,price
+1,3999
+2,5299
+3,3999
+4,1999
+5,999
+'
+actual=$(oomcli export --feature price --revision-id 1 --limit 5 -o csv)
+assert_eq "$case" "$expected" "$actual"
diff --git a/pkg/oomstore/apply_test.go b/pkg/oomstore/apply_test.go
index 0f6f94a0..745fe01f 100644
--- a/pkg/oomstore/apply_test.go
+++ b/pkg/oomstore/apply_test.go
@@ -574,10 +574,7 @@ items:
 	for _, tc := range testCases {
 		t.Run(tc.description, func(t *testing.T) {
 			stage, err := buildApplyStage(context.Background(), tc.opt)
-			if tc.wantErr != nil {
-				require.Error(t, err)
-				require.Equal(t, tc.wantErr.Error(), err.Error())
-			}
+			require.Equal(t, tc.wantErr, err)
 			require.Equal(t, tc.wantStage, stage)
 		})
 	}
diff --git a/pkg/oomstore/online_query_test.go b/pkg/oomstore/online_query_test.go
index 8d91da66..6bb3215f 100644
--- a/pkg/oomstore/online_query_test.go
+++ b/pkg/oomstore/online_query_test.go
@@ -37,14 +37,14 @@ func TestOnlineGet(t *testing.T) {
 		{
 			description: "no available features",
 			opt: types.OnlineGetOpt{
-				FeatureFullNames: []string{"a.f1", "a.f2"},
+				FeatureFullNames: []string{"f1", "f2"},
 				EntityKey:        "1234",
 			},
 			features:      nil,
 			expectedError: nil,
 			expected: &types.FeatureValues{
 				EntityKey:        "1234",
-				FeatureFullNames: []string{"a.f1", "a.f2"},
+				FeatureFullNames: []string{"f1", "f2"},
 				FeatureValueMap:  map[string]interface{}{},
 			},
 		},
@@ -124,7 +124,7 @@ func TestOnlineMultiGet(t *testing.T) {
 		{
 			description: "no available features, return nil",
 			opt: types.OnlineMultiGetOpt{
-				FeatureFullNames: []string{"a.f1", "a.f2"},
+				FeatureFullNames: []string{"f1", "f2"},
 				EntityKeys:       []string{"1234", "1235"},
 			},
 			features:      nil,
@@ -219,7 +219,6 @@ func prepareFeatures(isConsistent bool, isAvailable bool) types.FeatureList {
 	features := types.FeatureList{
 		{
 			Name:      "model",
-			FullName:  "device.model",
 			ValueType: types.String,
 			GroupID:   1,
 			Group: &types.Group{
@@ -232,7 +231,6 @@ func prepareFeatures(isConsistent bool, isAvailable bool) types.FeatureList {
 		},
 		{
 			Name:      "price",
-			FullName:  "device.price",
 			ValueType: types.Int64,
 			GroupID:   2,
 			Group: &types.Group{
@@ -245,7 +243,6 @@ func prepareFeatures(isConsistent bool, isAvailable bool) types.FeatureList {
 		},
 		{
 			Name:      "age",
-			FullName:  "user.age",
 			ValueType: types.Int64,
 			GroupID:   3,
 			Group: &types.Group{
diff --git a/pkg/oomstore/sync_test.go b/pkg/oomstore/sync_test.go
index 6f07ca13..0c78f316 100644
--- a/pkg/oomstore/sync_test.go
+++ b/pkg/oomstore/sync_test.go
@@ -134,11 +134,7 @@ func TestSync(t *testing.T) {
 		t.Run(tc.description, func(t *testing.T) {
 			metadataStore.EXPECT().Refresh().Return(nil).AnyTimes()
 			tc.mockFn()
-			err := store.Sync(ctx, tc.opt)
-			if tc.expectedError != nil {
-				require.Error(t, err)
-				require.Equal(t, tc.expectedError.Error(), err.Error())
-			}
+			require.Equal(t, tc.expectedError, store.Sync(ctx, tc.opt))
 		})
 	}
 }