func (l *Lease) hasNoOwner() bool {
	return l.Owner == "NULL" || l.Owner == ""
}
hasNoOwner return true if the current owner is null.
package lease
import (
	"errors"
	"time"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
)
type AttributeType int
const (
	StringSet AttributeType = iota
	NumberSet
	BinarySet
)
var (
	ErrTokenNotMatch = errors.New("leaser: concurrency token doesn't match the authoritative lease")
	ErrLeaseNotHeld = errors.New("leaser: worker does not hold the passed-in lease object")
	ErrValueNotMatch = errors.New("leaser: field value does not match the field type")
)
type Lease struct {
	Key     string `dynamodbav:"leaseKey"`
	Owner   string `dynamodbav:"leaseOwner"`
	Counter int    `dynamodbav:"leaseCounter"`
	lastRenewal time.Time
	concurrencyToken string
	extrafields map[string]interface{}
	explicitfields map[string]*dynamodb.AttributeValue
	removedfields []string
}
func NewLease(key string) Lease {
	return Lease{Key: key}
}
func (l *Lease) Set(key string, val interface{}) {
	if l.extrafields == nil {
		l.extrafields = make(map[string]interface{})
	}
	l.extrafields[key] = val
	delete(l.explicitfields, key)
}
func (l *Lease) SetAs(key string, val interface{}, typ AttributeType) error {
	if l.explicitfields == nil {
		l.explicitfields = make(map[string]*dynamodb.AttributeValue)
	}
	ok := false
	switch typ {
	case StringSet, NumberSet:
		var ss []string
		if ss, ok = val.([]string); ok {
			v := &dynamodb.AttributeValue{
				SS: aws.StringSlice(ss),
			}
			if typ == NumberSet {
				v = &dynamodb.AttributeValue{
					NS: aws.StringSlice(ss),
				}
			}
			l.explicitfields[key] = v
		}
	case BinarySet:
		var bs [][]byte
		if bs, ok = val.([][]byte); ok {
			l.explicitfields[key] = &dynamodb.AttributeValue{
				BS: bs,
			}
		}
	}
	if !ok {
		return ErrValueNotMatch
	}
	delete(l.extrafields, key)
	return nil
}
func (l *Lease) Get(key string) (interface{}, bool) {
	if val, ok := l.extrafields[key]; ok {
		return val, ok
	}
	if val, ok := l.explicitfields[key]; ok {
		var ret interface{}
		if val.NS != nil {
			ret = aws.StringValueSlice(val.NS)
		} else if val.SS != nil {
			ret = aws.StringValueSlice(val.SS)
		} else {
			ret = val.BS
		}
		return ret, ok
	}
	return nil, false
}
func (l *Lease) Del(key string) {
	var ok bool
	if _, ok = l.extrafields[key]; ok {
		delete(l.extrafields, key)
	} else if _, ok = l.explicitfields[key]; ok {
		delete(l.explicitfields, key)
	}
	if ok {
		l.removedfields = append(l.removedfields, key)
	}
}
func (l *Lease) isExpired(t time.Duration) bool {
	return time.Since(l.lastRenewal) > t
}