go.mercari.io/datastore@v1.8.2/boom/tx_aecompat.go (about)

     1  package boom
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"go.mercari.io/datastore"
     7  )
     8  
     9  // IMPORTANT NOTICE: You should use *boom.Transaction.
    10  
    11  var _ AECompatibleOperations = &Boom{}
    12  var _ AECompatibleOperations = &AECompatibleTransaction{}
    13  
    14  // AECompatibleOperations represents Transaction, if not, both common operations.
    15  // In AppEngine Datastore transactions immediately return Key.
    16  // In order to realize this, this wrapper internally performs AllocateID when it is required.
    17  //
    18  // This is for migrating existing code and should not be used if possible.
    19  type AECompatibleOperations interface {
    20  	Kind(src interface{}) string
    21  	Key(src interface{}) datastore.Key
    22  	KeyError(src interface{}) (datastore.Key, error)
    23  	Get(dst interface{}) error
    24  	GetMulti(dst interface{}) error
    25  	Put(src interface{}) (datastore.Key, error)
    26  	PutMulti(src interface{}) ([]datastore.Key, error)
    27  	Delete(src interface{}) error
    28  	DeleteMulti(src interface{}) error
    29  }
    30  
    31  // ToAECompatibleTransaction converts a transaction to AECompatibleTransaction.
    32  // AECompatibleTransaction implements AECompatibleOperations.
    33  func ToAECompatibleTransaction(tx *Transaction) *AECompatibleTransaction {
    34  	return &AECompatibleTransaction{bm: tx.bm, tx: tx.tx}
    35  }
    36  
    37  // AECompatibleTransaction implements AECompatibleOperations.
    38  // It is useful for migration when using AppEngine Datastore,
    39  // when using transactions or not using it with using the same code.
    40  type AECompatibleTransaction struct {
    41  	bm *Boom
    42  	tx datastore.Transaction
    43  }
    44  
    45  // Boom object that is the source of the Batch object is returned.
    46  func (tx *AECompatibleTransaction) Boom() *Boom {
    47  	return tx.bm
    48  }
    49  
    50  // Kind retrieves kind name from struct.
    51  func (tx *AECompatibleTransaction) Kind(src interface{}) string {
    52  	return tx.bm.Kind(src)
    53  }
    54  
    55  // Key retrieves datastore key from struct without error occurred.
    56  func (tx *AECompatibleTransaction) Key(src interface{}) datastore.Key {
    57  	return tx.bm.Key(src)
    58  }
    59  
    60  // KeyError retrieves datastore key from struct with error occurred.
    61  func (tx *AECompatibleTransaction) KeyError(src interface{}) (datastore.Key, error) {
    62  	return tx.bm.KeyError(src)
    63  }
    64  
    65  // Get loads the entity stored for key into dst, which must be a struct pointer or implement PropertyLoadSaver.
    66  // key will be extracted from dst.
    67  //
    68  // If there is no such entity for the key, Get returns ErrNoSuchEntity.
    69  // The values of dst's unmatched struct fields are not modified, and matching slice-typed fields are not reset before appending to them.
    70  // In particular, it is recommended to pass a pointer to a zero valued struct on each Get call.
    71  func (tx *AECompatibleTransaction) Get(dst interface{}) error {
    72  	dsts := []interface{}{dst}
    73  	err := tx.GetMulti(dsts)
    74  	if merr, ok := err.(datastore.MultiError); ok {
    75  		return merr[0]
    76  	} else if err != nil {
    77  		return err
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  // GetMulti is a batch version of Get.
    84  // key will be extracted from each struct of dst.
    85  //
    86  // dst must be a []S, []*S, []I or []P, for some struct type S, some interface type I, or some non-interface non-pointer type P such that P or *P implements PropertyLoadSaver.
    87  // If an []I, each element must be a valid dst for Get: it must be a struct pointer or implement PropertyLoadSaver.
    88  func (tx *AECompatibleTransaction) GetMulti(dst interface{}) error {
    89  	keys, err := tx.bm.extractKeys(dst)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	return tx.tx.GetMulti(keys, dst)
    95  }
    96  
    97  // Put saves the entity src into the datastore.
    98  // key will be extract from src struct.
    99  // src must be a struct pointer or implement PropertyLoadSaver; if a struct pointer then any unexported fields of that struct will be skipped.
   100  // If k is an incomplete key, the returned key will be a unique key generated by the datastore,
   101  // and inject key to src struct.
   102  func (tx *AECompatibleTransaction) Put(src interface{}) (datastore.Key, error) {
   103  	srcs := []interface{}{src}
   104  	keys, err := tx.PutMulti(srcs)
   105  	if merr, ok := err.(datastore.MultiError); ok {
   106  		return nil, merr[0]
   107  	} else if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	return keys[0], nil
   112  }
   113  
   114  // PutMulti is a batch version of Put.
   115  //
   116  // src must satisfy the same conditions as the dst argument to GetMulti.
   117  func (tx *AECompatibleTransaction) PutMulti(src interface{}) ([]datastore.Key, error) {
   118  	keys, err := tx.bm.extractKeys(src)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	// This api should returns []datastore.Key.
   124  	// Use AllocateIDs instead of []datastore.PendingKey.
   125  	incompleteIndexes := make([]int, 0, len(keys))
   126  	incompleteKeys := make([]datastore.Key, 0, len(keys))
   127  	for idx, key := range keys {
   128  		if key.Incomplete() {
   129  			incompleteIndexes = append(incompleteIndexes, idx)
   130  			incompleteKeys = append(incompleteKeys, key)
   131  		}
   132  	}
   133  	incompleteKeys, err = tx.bm.AllocateIDs(incompleteKeys)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	for idx, inIdx := range incompleteIndexes {
   138  		keys[inIdx] = incompleteKeys[idx]
   139  	}
   140  
   141  	_, err = tx.tx.PutMulti(keys, src)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	v := reflect.Indirect(reflect.ValueOf(src))
   147  	for idx, key := range keys {
   148  		err = tx.bm.setStructKey(v.Index(idx).Interface(), key)
   149  		if err != nil {
   150  			return nil, err
   151  		}
   152  	}
   153  
   154  	return keys, nil
   155  }
   156  
   157  // Delete deletes the entity.
   158  // key will be extract from src struct.
   159  func (tx *AECompatibleTransaction) Delete(src interface{}) error {
   160  	srcs := []interface{}{src}
   161  	err := tx.DeleteMulti(srcs)
   162  	if merr, ok := err.(datastore.MultiError); ok {
   163  		return merr[0]
   164  	} else if err != nil {
   165  		return err
   166  	}
   167  
   168  	return nil
   169  }
   170  
   171  // DeleteMulti is a batch version of Delete.
   172  func (tx *AECompatibleTransaction) DeleteMulti(src interface{}) error {
   173  	keys, err := tx.bm.extractKeys(src)
   174  	if err != nil {
   175  		return err
   176  	}
   177  
   178  	return tx.tx.DeleteMulti(keys)
   179  }
   180  
   181  // Commit applies the enqueued operations atomically.
   182  func (tx *AECompatibleTransaction) Commit() (datastore.Commit, error) {
   183  	commit, err := tx.tx.Commit()
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  
   188  	return commit, nil
   189  }
   190  
   191  // Rollback abandons a pending transaction.
   192  func (tx *AECompatibleTransaction) Rollback() error {
   193  	return tx.tx.Rollback()
   194  }