github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/life_ns.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/mgo/v3"
     9  	"github.com/juju/mgo/v3/bson"
    10  	"github.com/juju/mgo/v3/txn"
    11  
    12  	"github.com/juju/juju/mongo"
    13  )
    14  
    15  // nsLife_ backs nsLife.
    16  type nsLife_ struct{}
    17  
    18  // nsLife namespaces low-level entity-life functionality. See the
    19  // discussion in nsPayloads: this exists not to be the one place for
    20  // life functionality (that would be a huge change), but to at least
    21  // represent the parts we need for payloads in a consistent fashion.
    22  //
    23  // Both the namespacing and the explicit Collection->op approach seem
    24  // to be good ideas, and should ideally be extended as we continue.
    25  var nsLife = nsLife_{}
    26  
    27  // destroyOp returns errNotAlive if the identified entity is not Alive;
    28  // or a txn.Op that will fail if the condition no longer holds, and
    29  // otherwise set Life to Dying and make any other updates supplied in
    30  // update.
    31  func (nsLife_) destroyOp(entities mongo.Collection, docID string, update bson.D) (txn.Op, error) {
    32  	op, err := nsLife.aliveOp(entities, docID)
    33  	if err != nil {
    34  		return txn.Op{}, errors.Trace(err)
    35  	}
    36  	setDying := bson.D{{"$set", bson.D{{"life", Dying}}}}
    37  	op.Update = append(setDying, update...)
    38  	return op, nil
    39  }
    40  
    41  // aliveOp returns errNotAlive if the identified entity is not Alive; or
    42  // a txn.Op that will fail if the condition no longer holds.
    43  func (nsLife_) aliveOp(entities mongo.Collection, docID string) (txn.Op, error) {
    44  	op, err := nsLife.checkOp(entities, docID, nsLife.alive())
    45  	switch errors.Cause(err) {
    46  	case nil:
    47  	case errCheckFailed:
    48  		return txn.Op{}, notAliveErr
    49  	default:
    50  		return txn.Op{}, errors.Trace(err)
    51  	}
    52  	return op, nil
    53  }
    54  
    55  // notDeadOp returns errDeadOrGone if the identified entity is not Alive
    56  // or Dying, or a txn.Op that will fail if the condition no longer
    57  // holds.
    58  func (nsLife_) notDeadOp(entities mongo.Collection, docID string) (txn.Op, error) {
    59  	op, err := nsLife.checkOp(entities, docID, nsLife.notDead())
    60  	switch errors.Cause(err) {
    61  	case nil:
    62  	case errCheckFailed:
    63  		return txn.Op{}, errDeadOrGone
    64  	default:
    65  		return txn.Op{}, errors.Trace(err)
    66  	}
    67  	return op, nil
    68  }
    69  
    70  var errCheckFailed = errors.New("check failed")
    71  
    72  func (nsLife_) checkOp(entities mongo.Collection, docID string, check bson.D) (txn.Op, error) {
    73  	sel := append(bson.D{{"_id", docID}}, check...)
    74  	count, err := entities.Find(sel).Count()
    75  	if err != nil {
    76  		return txn.Op{}, errors.Trace(err)
    77  	} else if count == 0 {
    78  		return txn.Op{}, errCheckFailed
    79  	}
    80  	return txn.Op{
    81  		C:      entities.Name(),
    82  		Id:     docID,
    83  		Assert: check,
    84  	}, nil
    85  }
    86  
    87  func (nsLife_) read(entities mongo.Collection, docID string) (Life, error) {
    88  	var doc struct {
    89  		Life Life `bson:"life"`
    90  	}
    91  	err := entities.FindId(docID).One(&doc)
    92  	switch errors.Cause(err) {
    93  	case nil:
    94  	case mgo.ErrNotFound:
    95  		return Dead, errors.NotFoundf("entity")
    96  	default:
    97  		return Dead, errors.Trace(err)
    98  	}
    99  	return doc.Life, nil
   100  }
   101  
   102  // alive returns a selector that matches only documents whose life
   103  // field is set to Alive.
   104  func (nsLife_) alive() bson.D {
   105  	return bson.D{{"life", Alive}}
   106  }
   107  
   108  // notDead returns a selector that matches only documents whose life
   109  // field is not set to Dead.
   110  func (nsLife_) notDead() bson.D {
   111  	return bson.D{{"life", bson.D{{"$ne", Dead}}}}
   112  }