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 }