Label store config & RDBMS implementation
This commit is contained in:
parent
ae4a07a3f7
commit
d89cc6e207
@ -16,6 +16,7 @@ package store
|
||||
// - store/compose_record_values.yaml
|
||||
// - store/compose_records.yaml
|
||||
// - store/credentials.yaml
|
||||
// - store/labels.yaml
|
||||
// - store/messaging_attachments.yaml
|
||||
// - store/messaging_channel_members.yaml
|
||||
// - store/messaging_channels.yaml
|
||||
@ -50,6 +51,7 @@ type (
|
||||
ComposeRecordValues
|
||||
ComposeRecords
|
||||
Credentials
|
||||
Labels
|
||||
MessagingAttachments
|
||||
MessagingChannelMembers
|
||||
MessagingChannels
|
||||
|
||||
84
store/labels.gen.go
Normal file
84
store/labels.gen.go
Normal file
@ -0,0 +1,84 @@
|
||||
package store
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Template: pkg/codegen/assets/store_base.gen.go.tpl
|
||||
// Definitions: store/labels.yaml
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/cortezaproject/corteza-server/pkg/label/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Labels interface {
|
||||
SearchLabels(ctx context.Context, f types.LabelFilter) (types.LabelSet, types.LabelFilter, error)
|
||||
LookupLabelByKindResourceIDName(ctx context.Context, kind string, resource_id uint64, name string) (*types.Label, error)
|
||||
|
||||
CreateLabel(ctx context.Context, rr ...*types.Label) error
|
||||
|
||||
UpdateLabel(ctx context.Context, rr ...*types.Label) error
|
||||
|
||||
UpsertLabel(ctx context.Context, rr ...*types.Label) error
|
||||
|
||||
DeleteLabel(ctx context.Context, rr ...*types.Label) error
|
||||
DeleteLabelByKindResourceIDName(ctx context.Context, kind string, resourceID uint64, name string) error
|
||||
|
||||
TruncateLabels(ctx context.Context) error
|
||||
|
||||
// Additional custom functions
|
||||
|
||||
// DeleteExtraLabels (custom function)
|
||||
DeleteExtraLabels(ctx context.Context, _kind string, _resourceID uint64, _names ...string) error
|
||||
}
|
||||
)
|
||||
|
||||
var _ *types.Label
|
||||
var _ context.Context
|
||||
|
||||
// SearchLabels returns all matching Labels from store
|
||||
func SearchLabels(ctx context.Context, s Labels, f types.LabelFilter) (types.LabelSet, types.LabelFilter, error) {
|
||||
return s.SearchLabels(ctx, f)
|
||||
}
|
||||
|
||||
// LookupLabelByKindResourceIDName Label lookup by kind, resource, name
|
||||
func LookupLabelByKindResourceIDName(ctx context.Context, s Labels, kind string, resource_id uint64, name string) (*types.Label, error) {
|
||||
return s.LookupLabelByKindResourceIDName(ctx, kind, resource_id, name)
|
||||
}
|
||||
|
||||
// CreateLabel creates one or more Labels in store
|
||||
func CreateLabel(ctx context.Context, s Labels, rr ...*types.Label) error {
|
||||
return s.CreateLabel(ctx, rr...)
|
||||
}
|
||||
|
||||
// UpdateLabel updates one or more (existing) Labels in store
|
||||
func UpdateLabel(ctx context.Context, s Labels, rr ...*types.Label) error {
|
||||
return s.UpdateLabel(ctx, rr...)
|
||||
}
|
||||
|
||||
// UpsertLabel creates new or updates existing one or more Labels in store
|
||||
func UpsertLabel(ctx context.Context, s Labels, rr ...*types.Label) error {
|
||||
return s.UpsertLabel(ctx, rr...)
|
||||
}
|
||||
|
||||
// DeleteLabel Deletes one or more Labels from store
|
||||
func DeleteLabel(ctx context.Context, s Labels, rr ...*types.Label) error {
|
||||
return s.DeleteLabel(ctx, rr...)
|
||||
}
|
||||
|
||||
// DeleteLabelByKindResourceIDName Deletes Label from store
|
||||
func DeleteLabelByKindResourceIDName(ctx context.Context, s Labels, kind string, resourceID uint64, name string) error {
|
||||
return s.DeleteLabelByKindResourceIDName(ctx, kind, resourceID, name)
|
||||
}
|
||||
|
||||
// TruncateLabels Deletes all Labels from store
|
||||
func TruncateLabels(ctx context.Context, s Labels) error {
|
||||
return s.TruncateLabels(ctx)
|
||||
}
|
||||
|
||||
func DeleteExtraLabels(ctx context.Context, s Labels, _kind string, _resourceID uint64, _names ...string) error {
|
||||
return s.DeleteExtraLabels(ctx, _kind, _resourceID, _names...)
|
||||
}
|
||||
39
store/labels.yaml
Normal file
39
store/labels.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
import:
|
||||
- github.com/cortezaproject/corteza-server/pkg/label/types
|
||||
|
||||
types:
|
||||
type: types.Label
|
||||
|
||||
fields:
|
||||
- { field: Kind, isPrimaryKey: true }
|
||||
- { field: ResourceID, isPrimaryKey: true }
|
||||
- { field: Name, isPrimaryKey: true, lookupFilterPreprocessor: lower }
|
||||
- { field: Value }
|
||||
|
||||
lookups:
|
||||
- fields: [ Kind, ResourceID, Name ]
|
||||
uniqueConstraintCheck: true
|
||||
description: |-
|
||||
Label lookup by kind, resource, name
|
||||
|
||||
functions:
|
||||
- name: DeleteExtraLabels
|
||||
arguments:
|
||||
- { name: kind, type: string }
|
||||
- { name: resourceID, type: uint64 }
|
||||
- { name: names, type: ...string }
|
||||
return: [ error ]
|
||||
|
||||
|
||||
search:
|
||||
enablePaging: false
|
||||
enableSorting: false
|
||||
enableFilterCheckFunction: false
|
||||
|
||||
upsert:
|
||||
enable: true
|
||||
|
||||
rdbms:
|
||||
alias: lbl
|
||||
table: labels
|
||||
customFilterConverter: true
|
||||
344
store/rdbms/labels.gen.go
Normal file
344
store/rdbms/labels.gen.go
Normal file
@ -0,0 +1,344 @@
|
||||
package rdbms
|
||||
|
||||
// This file is an auto-generated file
|
||||
//
|
||||
// Template: pkg/codegen/assets/store_rdbms.gen.go.tpl
|
||||
// Definitions: store/labels.yaml
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/cortezaproject/corteza-server/pkg/label/types"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
)
|
||||
|
||||
var _ = errors.Is
|
||||
|
||||
// SearchLabels returns all matching rows
|
||||
//
|
||||
// This function calls convertLabelFilter with the given
|
||||
// types.LabelFilter and expects to receive a working squirrel.SelectBuilder
|
||||
func (s Store) SearchLabels(ctx context.Context, f types.LabelFilter) (types.LabelSet, types.LabelFilter, error) {
|
||||
var (
|
||||
err error
|
||||
set []*types.Label
|
||||
q squirrel.SelectBuilder
|
||||
)
|
||||
q, err = s.convertLabelFilter(f)
|
||||
if err != nil {
|
||||
return nil, f, err
|
||||
}
|
||||
|
||||
return set, f, s.config.ErrorHandler(func() error {
|
||||
set, _, _, err = s.QueryLabels(ctx, q, nil)
|
||||
return err
|
||||
|
||||
}())
|
||||
}
|
||||
|
||||
// QueryLabels queries the database, converts and checks each row and
|
||||
// returns collected set
|
||||
//
|
||||
// Fn also returns total number of fetched items and last fetched item so that the caller can construct cursor
|
||||
// for next page of results
|
||||
func (s Store) QueryLabels(
|
||||
ctx context.Context,
|
||||
q squirrel.Sqlizer,
|
||||
check func(*types.Label) (bool, error),
|
||||
) ([]*types.Label, uint, *types.Label, error) {
|
||||
var (
|
||||
set = make([]*types.Label, 0, DefaultSliceCapacity)
|
||||
res *types.Label
|
||||
|
||||
// Query rows with
|
||||
rows, err = s.Query(ctx, q)
|
||||
|
||||
fetched uint
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
fetched++
|
||||
if err = rows.Err(); err == nil {
|
||||
res, err = s.internalLabelRowScanner(rows)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
|
||||
set = append(set, res)
|
||||
}
|
||||
|
||||
return set, fetched, res, rows.Err()
|
||||
}
|
||||
|
||||
// LookupLabelByKindResourceIDName Label lookup by kind, resource, name
|
||||
func (s Store) LookupLabelByKindResourceIDName(ctx context.Context, kind string, resource_id uint64, name string) (*types.Label, error) {
|
||||
return s.execLookupLabel(ctx, squirrel.Eq{
|
||||
s.preprocessColumn("lbl.kind", ""): store.PreprocessValue(kind, ""),
|
||||
s.preprocessColumn("lbl.rel_resource", ""): store.PreprocessValue(resource_id, ""),
|
||||
s.preprocessColumn("lbl.name", "lower"): store.PreprocessValue(name, "lower"),
|
||||
})
|
||||
}
|
||||
|
||||
// CreateLabel creates one or more rows in labels table
|
||||
func (s Store) CreateLabel(ctx context.Context, rr ...*types.Label) (err error) {
|
||||
for _, res := range rr {
|
||||
err = s.checkLabelConstraints(ctx, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.execCreateLabels(ctx, s.internalLabelEncoder(res))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateLabel updates one or more existing rows in labels
|
||||
func (s Store) UpdateLabel(ctx context.Context, rr ...*types.Label) error {
|
||||
return s.config.ErrorHandler(s.partialLabelUpdate(ctx, nil, rr...))
|
||||
}
|
||||
|
||||
// partialLabelUpdate updates one or more existing rows in labels
|
||||
func (s Store) partialLabelUpdate(ctx context.Context, onlyColumns []string, rr ...*types.Label) (err error) {
|
||||
for _, res := range rr {
|
||||
err = s.checkLabelConstraints(ctx, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.execUpdateLabels(
|
||||
ctx,
|
||||
squirrel.Eq{
|
||||
s.preprocessColumn("lbl.kind", ""): store.PreprocessValue(res.Kind, ""), s.preprocessColumn("lbl.rel_resource", ""): store.PreprocessValue(res.ResourceID, ""), s.preprocessColumn("lbl.name", "lower"): store.PreprocessValue(res.Name, "lower"),
|
||||
},
|
||||
s.internalLabelEncoder(res).Skip("kind", "rel_resource", "name").Only(onlyColumns...))
|
||||
if err != nil {
|
||||
return s.config.ErrorHandler(err)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpsertLabel updates one or more existing rows in labels
|
||||
func (s Store) UpsertLabel(ctx context.Context, rr ...*types.Label) (err error) {
|
||||
for _, res := range rr {
|
||||
err = s.checkLabelConstraints(ctx, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.config.ErrorHandler(s.execUpsertLabels(ctx, s.internalLabelEncoder(res)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteLabel Deletes one or more rows from labels table
|
||||
func (s Store) DeleteLabel(ctx context.Context, rr ...*types.Label) (err error) {
|
||||
for _, res := range rr {
|
||||
|
||||
err = s.execDeleteLabels(ctx, squirrel.Eq{
|
||||
s.preprocessColumn("lbl.kind", ""): store.PreprocessValue(res.Kind, ""), s.preprocessColumn("lbl.rel_resource", ""): store.PreprocessValue(res.ResourceID, ""), s.preprocessColumn("lbl.name", "lower"): store.PreprocessValue(res.Name, "lower"),
|
||||
})
|
||||
if err != nil {
|
||||
return s.config.ErrorHandler(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteLabelByKindResourceIDName Deletes row from the labels table
|
||||
func (s Store) DeleteLabelByKindResourceIDName(ctx context.Context, kind string, resourceID uint64, name string) error {
|
||||
return s.execDeleteLabels(ctx, squirrel.Eq{
|
||||
s.preprocessColumn("lbl.kind", ""): store.PreprocessValue(kind, ""),
|
||||
s.preprocessColumn("lbl.rel_resource", ""): store.PreprocessValue(resourceID, ""),
|
||||
s.preprocessColumn("lbl.name", "lower"): store.PreprocessValue(name, "lower"),
|
||||
})
|
||||
}
|
||||
|
||||
// TruncateLabels Deletes all rows from the labels table
|
||||
func (s Store) TruncateLabels(ctx context.Context) error {
|
||||
return s.config.ErrorHandler(s.Truncate(ctx, s.labelTable()))
|
||||
}
|
||||
|
||||
// execLookupLabel prepares Label query and executes it,
|
||||
// returning types.Label (or error)
|
||||
func (s Store) execLookupLabel(ctx context.Context, cnd squirrel.Sqlizer) (res *types.Label, err error) {
|
||||
var (
|
||||
row rowScanner
|
||||
)
|
||||
|
||||
row, err = s.QueryRow(ctx, s.labelsSelectBuilder().Where(cnd))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res, err = s.internalLabelRowScanner(row)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// execCreateLabels updates all matched (by cnd) rows in labels with given data
|
||||
func (s Store) execCreateLabels(ctx context.Context, payload store.Payload) error {
|
||||
return s.config.ErrorHandler(s.Exec(ctx, s.InsertBuilder(s.labelTable()).SetMap(payload)))
|
||||
}
|
||||
|
||||
// execUpdateLabels updates all matched (by cnd) rows in labels with given data
|
||||
func (s Store) execUpdateLabels(ctx context.Context, cnd squirrel.Sqlizer, set store.Payload) error {
|
||||
return s.config.ErrorHandler(s.Exec(ctx, s.UpdateBuilder(s.labelTable("lbl")).Where(cnd).SetMap(set)))
|
||||
}
|
||||
|
||||
// execUpsertLabels inserts new or updates matching (by-primary-key) rows in labels with given data
|
||||
func (s Store) execUpsertLabels(ctx context.Context, set store.Payload) error {
|
||||
upsert, err := s.config.UpsertBuilder(
|
||||
s.config,
|
||||
s.labelTable(),
|
||||
set,
|
||||
"kind",
|
||||
"rel_resource",
|
||||
"name",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.config.ErrorHandler(s.Exec(ctx, upsert))
|
||||
}
|
||||
|
||||
// execDeleteLabels Deletes all matched (by cnd) rows in labels with given data
|
||||
func (s Store) execDeleteLabels(ctx context.Context, cnd squirrel.Sqlizer) error {
|
||||
return s.config.ErrorHandler(s.Exec(ctx, s.DeleteBuilder(s.labelTable("lbl")).Where(cnd)))
|
||||
}
|
||||
|
||||
func (s Store) internalLabelRowScanner(row rowScanner) (res *types.Label, err error) {
|
||||
res = &types.Label{}
|
||||
|
||||
if _, has := s.config.RowScanners["label"]; has {
|
||||
scanner := s.config.RowScanners["label"].(func(_ rowScanner, _ *types.Label) error)
|
||||
err = scanner(row, res)
|
||||
} else {
|
||||
err = row.Scan(
|
||||
&res.Kind,
|
||||
&res.ResourceID,
|
||||
&res.Name,
|
||||
&res.Value,
|
||||
)
|
||||
}
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not scan db row for Label: %w", err)
|
||||
} else {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
// QueryLabels returns squirrel.SelectBuilder with set table and all columns
|
||||
func (s Store) labelsSelectBuilder() squirrel.SelectBuilder {
|
||||
return s.SelectBuilder(s.labelTable("lbl"), s.labelColumns("lbl")...)
|
||||
}
|
||||
|
||||
// labelTable name of the db table
|
||||
func (Store) labelTable(aa ...string) string {
|
||||
var alias string
|
||||
if len(aa) > 0 {
|
||||
alias = " AS " + aa[0]
|
||||
}
|
||||
|
||||
return "labels" + alias
|
||||
}
|
||||
|
||||
// LabelColumns returns all defined table columns
|
||||
//
|
||||
// With optional string arg, all columns are returned aliased
|
||||
func (Store) labelColumns(aa ...string) []string {
|
||||
var alias string
|
||||
if len(aa) > 0 {
|
||||
alias = aa[0] + "."
|
||||
}
|
||||
|
||||
return []string{
|
||||
alias + "kind",
|
||||
alias + "rel_resource",
|
||||
alias + "name",
|
||||
alias + "value",
|
||||
}
|
||||
}
|
||||
|
||||
// {true true false false false}
|
||||
|
||||
// internalLabelEncoder encodes fields from types.Label to store.Payload (map)
|
||||
//
|
||||
// Encoding is done by using generic approach or by calling encodeLabel
|
||||
// func when rdbms.customEncoder=true
|
||||
func (s Store) internalLabelEncoder(res *types.Label) store.Payload {
|
||||
return store.Payload{
|
||||
"kind": res.Kind,
|
||||
"rel_resource": res.ResourceID,
|
||||
"name": res.Name,
|
||||
"value": res.Value,
|
||||
}
|
||||
}
|
||||
|
||||
// checkLabelConstraints performs lookups (on valid) resource to check if any of the values on unique fields
|
||||
// already exists in the store
|
||||
//
|
||||
// Using built-in constraint checking would be more performant but unfortunately we can not rely
|
||||
// on the full support (MySQL does not support conditional indexes)
|
||||
func (s *Store) checkLabelConstraints(ctx context.Context, res *types.Label) error {
|
||||
// Consider resource valid when all fields in unique constraint check lookups
|
||||
// have valid (non-empty) value
|
||||
//
|
||||
// Only string and uint64 are supported for now
|
||||
// feel free to add additional types if needed
|
||||
var valid = true
|
||||
|
||||
valid = valid && len(res.Kind) > 0
|
||||
|
||||
valid = valid && res.ResourceID > 0
|
||||
|
||||
valid = valid && len(res.Name) > 0
|
||||
|
||||
if !valid {
|
||||
return nil
|
||||
}
|
||||
|
||||
{
|
||||
ex, err := s.LookupLabelByKindResourceIDName(ctx, res.Kind, res.ResourceID, res.Name)
|
||||
if err == nil && ex != nil && ex.Kind != res.Kind && ex.ResourceID != res.ResourceID && ex.Name != res.Name {
|
||||
return store.ErrNotUnique
|
||||
} else if !errors.Is(err, store.ErrNotFound) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
41
store/rdbms/labels.go
Normal file
41
store/rdbms/labels.go
Normal file
@ -0,0 +1,41 @@
|
||||
package rdbms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/cortezaproject/corteza-server/pkg/label/types"
|
||||
)
|
||||
|
||||
func (s Store) convertLabelFilter(f types.LabelFilter) (query squirrel.SelectBuilder, err error) {
|
||||
query = s.labelsSelectBuilder()
|
||||
|
||||
query = query.Where(squirrel.Eq{"lbl.kind": f.Kind})
|
||||
|
||||
if len(f.ResourceID) > 0 {
|
||||
query = query.Where(squirrel.Eq{"lbl.rel_resource": f.ResourceID})
|
||||
}
|
||||
|
||||
if len(f.Filter) > 0 {
|
||||
kvOr := squirrel.Or{}
|
||||
for k, v := range f.Filter {
|
||||
kvOr = append(kvOr, squirrel.Eq{"name": k, "value": v})
|
||||
}
|
||||
query = query.Where(kvOr)
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteExtraLabels removes all unlisted labels
|
||||
func (s Store) DeleteExtraLabels(ctx context.Context, kind string, resourceID uint64, names ...string) (err error) {
|
||||
return s.execDeleteLabels(ctx, squirrel.And{
|
||||
squirrel.Eq{
|
||||
"kind": kind,
|
||||
"rel_resource": resourceID,
|
||||
},
|
||||
squirrel.NotEq{
|
||||
"name": names,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -56,6 +56,7 @@ func (s Schema) Tables() []*Table {
|
||||
s.ActionLog(),
|
||||
s.RbacRules(),
|
||||
s.Settings(),
|
||||
s.Labels(),
|
||||
s.ComposeAttachment(),
|
||||
s.ComposeChart(),
|
||||
s.ComposeModule(),
|
||||
@ -220,6 +221,17 @@ func (Schema) Settings() *Table {
|
||||
)
|
||||
}
|
||||
|
||||
func (Schema) Labels() *Table {
|
||||
return TableDef("labels",
|
||||
ColumnDef("kind", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
ColumnDef("rel_resource", ColumnTypeIdentifier),
|
||||
ColumnDef("name", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
ColumnDef("value", ColumnTypeText),
|
||||
|
||||
PrimaryKey(IColumn("kind", "rel_resource", "name")),
|
||||
)
|
||||
}
|
||||
|
||||
func (Schema) ComposeAttachment() *Table {
|
||||
// @todo merge with general attachment table
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ package tests
|
||||
// - store/compose_namespaces.yaml
|
||||
// - store/compose_pages.yaml
|
||||
// - store/credentials.yaml
|
||||
// - store/labels.yaml
|
||||
// - store/messaging_attachments.yaml
|
||||
// - store/messaging_channel_members.yaml
|
||||
// - store/messaging_channels.yaml
|
||||
@ -100,6 +101,11 @@ func testAllGenerated(t *testing.T, s store.Storer) {
|
||||
testCredentials(t, s)
|
||||
})
|
||||
|
||||
// Run generated tests for Labels
|
||||
t.Run("Labels", func(t *testing.T) {
|
||||
testLabels(t, s)
|
||||
})
|
||||
|
||||
// Run generated tests for MessagingAttachments
|
||||
t.Run("MessagingAttachments", func(t *testing.T) {
|
||||
testMessagingAttachments(t, s)
|
||||
|
||||
49
store/tests/labels_test.go
Normal file
49
store/tests/labels_test.go
Normal file
@ -0,0 +1,49 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/cortezaproject/corteza-server/pkg/label/types"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testLabels(t *testing.T, s store.Labels) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
t.Run("create", func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
req.NoError(s.TruncateLabels(ctx))
|
||||
req.NoError(s.CreateLabel(ctx, &types.Label{
|
||||
Kind: "kind",
|
||||
ResourceID: 1,
|
||||
Name: "lname",
|
||||
Value: "lvalue",
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("update", func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
req.NoError(s.TruncateLabels(ctx))
|
||||
req.NoError(s.UpdateLabel(ctx, &types.Label{
|
||||
Kind: "kind",
|
||||
ResourceID: 1,
|
||||
Name: "lname",
|
||||
Value: "lvalue",
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("upsert", func(t *testing.T) {
|
||||
req := require.New(t)
|
||||
req.NoError(s.TruncateLabels(ctx))
|
||||
req.NoError(s.UpsertLabel(ctx, &types.Label{
|
||||
Kind: "kind",
|
||||
ResourceID: 1,
|
||||
Name: "lname",
|
||||
Value: "lvalue",
|
||||
}))
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user