46 lines
1.2 KiB
Go
46 lines
1.2 KiB
Go
|
package tdb
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
type uniqueConstraint struct {
|
||
|
table *table
|
||
|
field dbField
|
||
|
index indexish
|
||
|
}
|
||
|
|
||
|
func newUniqueConstraint(table *table, index indexish, field dbField) (constraintish, error) {
|
||
|
if table == nil {
|
||
|
return nil, errors.New("[constraint] [unique] unable to create without table")
|
||
|
}
|
||
|
if index == nil {
|
||
|
return nil, fmt.Errorf("[constraint] [unique] is only valid for indicies (to avoid full table scans)")
|
||
|
}
|
||
|
|
||
|
return &uniqueConstraint{
|
||
|
table: table,
|
||
|
field: field,
|
||
|
index: index,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (c *uniqueConstraint) validate(tx *Tx, pv dbPtrValue) error {
|
||
|
indexedVals := c.index.indexedValues(pv)
|
||
|
keyValue := c.index.keyValue(pv)
|
||
|
for _, indexedVal := range indexedVals {
|
||
|
if err := c.index.iteratePrefixed(tx, indexedVal, func(indexed []byte) (IterationSignal, error) {
|
||
|
if !bytes.Equal(keyValue, indexed) {
|
||
|
c.table.debugLogf("[constraint] [unique] violation: record with '%s'.'%s' = '%s' already exists (id: %s)", c.table.name, c.field.Name, indexedVal, indexed)
|
||
|
return StopIteration, fmt.Errorf("[constraint] [unique] violation for field '%s'.'%s'", c.table.name, c.field.Name)
|
||
|
}
|
||
|
return StopIteration, nil
|
||
|
}); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|