func (c *Collection) UpdateAtKey(key, columnName string, fn func(v Cursor) error) error {
	return c.Query(func(txn *Txn) error {
		return txn.UpdateAtKey(key, columnName, fn)
	})
}
UpdateAtKey updates a specific row by initiating a separate transaction for the update.
package column
import (
	"context"
	"fmt"
	"math/bits"
	"reflect"
	"sync"
	"sync/atomic"
	"time"
	"github.com/kelindar/bitmap"
	"github.com/kelindar/column/commit"
	"github.com/kelindar/smutex"
)
type Object = map[string]interface{}
const (
	expireColumn = "expire"
	rowColumn    = "row"
)
type Collection struct {
	count  uint64              
	txns   *txnPool            
	lock   sync.RWMutex        
	slock  *smutex.SMutex128   
	cols   columns             
	fill   bitmap.Bitmap       
	size   int                 
	writer commit.Writer       
	pk     *columnKey          
	cancel context.CancelFunc  
}
type Options struct {
	Capacity int            
	Writer   commit.Writer  
	Vacuum   time.Duration  
}
func NewCollection(opts ...Options) *Collection {
	options := Options{
		Capacity: 1024,
		Vacuum:   1 * time.Second,
		Writer:   nil,
	}
	for _, o := range opts {
		if o.Capacity > 0 {
			options.Capacity = o.Capacity
		}
		if o.Vacuum > 0 {
			options.Vacuum = o.Vacuum
		}
		if o.Writer != nil {
			options.Writer = o.Writer
		}
	}
	ctx, cancel := context.WithCancel(context.Background())
	store := &Collection{
		cols:   makeColumns(8),
		txns:   newTxnPool(),
		size:   options.Capacity,
		slock:  new(smutex.SMutex128),
		fill:   make(bitmap.Bitmap, 0, options.Capacity>>6),
		writer: options.Writer,
		cancel: cancel,
	}
	store.CreateColumn(expireColumn, ForInt64())
	go store.vacuum(ctx, options.Vacuum)
	return store
}
func (c *Collection) next() uint32 {
	c.lock.Lock()
	idx := c.findFreeIndex(atomic.AddUint64(&c.count, 1))
	c.fill.Set(idx)
	c.lock.Unlock()
	return idx
}
func (c *Collection) findFreeIndex(count uint64) uint32 {
	fillSize := len(c.fill)
	if count > uint64(fillSize)<<6 {
		return uint32(len(c.fill)) << 6
	}
	if fillSize > 0 {
		if tail := c.fill[fillSize-1]; tail != 0xffffffffffffffff {
			return uint32((fillSize-1)<<6 + bits.TrailingZeros64(^tail))
		}
	}
	idx, _ := c.fill.MinZero()
	return idx
}
func (c *Collection) InsertObject(obj Object) (index uint32) {
	c.Query(func(txn *Txn) error {
		index, _ = txn.InsertObject(obj)
		return nil
	})
	return
}
func (c *Collection) InsertObjectWithTTL(obj Object, ttl time.Duration) (index uint32) {
	c.Query(func(txn *Txn) error {
		index, _ = txn.InsertObjectWithTTL(obj, ttl)
		return nil
	})
	return
}
func (c *Collection) Insert(columnName string, fn func(v Cursor) error) (index uint32, err error) {
	err = c.Query(func(txn *Txn) (innerErr error) {
		index, innerErr = txn.Insert(columnName, fn)
		return
	})
	return
}
func (c *Collection) InsertWithTTL(columnName string, ttl time.Duration, fn func(v Cursor) error) (index uint32, err error) {
	err = c.Query(func(txn *Txn) (innerErr error) {
		index, innerErr = txn.InsertWithTTL(columnName, ttl, fn)
		return
	})
	return
}
func (c *Collection) UpdateAt(idx uint32, columnName string, fn func(v Cursor) error) error {
	return c.Query(func(txn *Txn) error {
		return txn.UpdateAt(idx, columnName, fn)
	})
}