Files
chaisql/internal/stream/index/validate.go
2024-02-17 17:56:41 +04:00

95 lines
2.0 KiB
Go

package index
import (
"fmt"
"github.com/chaisql/chai/internal/database"
"github.com/chaisql/chai/internal/environment"
"github.com/chaisql/chai/internal/stream"
"github.com/chaisql/chai/internal/types"
"github.com/cockroachdb/errors"
)
// ValidateOperator reads the input stream and deletes the object from the specified index.
type ValidateOperator struct {
stream.BaseOperator
indexName string
}
func Validate(indexName string) *ValidateOperator {
return &ValidateOperator{
indexName: indexName,
}
}
func (op *ValidateOperator) Clone() stream.Operator {
return &ValidateOperator{
BaseOperator: op.BaseOperator.Clone(),
indexName: op.indexName,
}
}
func (op *ValidateOperator) Iterate(in *environment.Environment, fn func(out *environment.Environment) error) error {
tx := in.GetTx()
info, err := tx.Catalog.GetIndexInfo(op.indexName)
if err != nil {
return err
}
if !info.Unique {
return errors.New("indexValidate can be used only on unique indexes")
}
idx, err := tx.Catalog.GetIndex(tx, op.indexName)
if err != nil {
return err
}
return op.Prev.Iterate(in, func(out *environment.Environment) error {
r, ok := out.GetRow()
if !ok {
return errors.New("missing row")
}
vs := make([]types.Value, 0, len(info.Columns))
// if the indexes values contain NULL somewhere,
// we don't check for unicity.
// cf: https://sqlite.org/lang_createindex.html#unique_indexes
var hasNull bool
for _, column := range info.Columns {
v, err := r.Get(column)
if err != nil {
hasNull = true
v = types.NewNullValue()
} else if v.Type() == types.TypeNull {
hasNull = true
}
vs = append(vs, v)
}
if !hasNull {
duplicate, key, err := idx.Exists(vs)
if err != nil {
return err
}
if duplicate {
return &database.ConstraintViolationError{
Constraint: "UNIQUE",
Columns: info.Columns,
Key: key,
}
}
}
return fn(out)
})
}
func (op *ValidateOperator) String() string {
return fmt.Sprintf("index.Validate(%q)", op.indexName)
}