github.com/condensat/bank-core@v0.1.0/database/query/batch.go (about)

     1  // Copyright 2020 Condensat Tech. All rights reserved.
     2  // Use of this source code is governed by a MIT
     3  // license that can be found in the LICENSE file.
     4  
     5  package query
     6  
     7  import (
     8  	"errors"
     9  	"time"
    10  
    11  	"github.com/condensat/bank-core/database"
    12  	"github.com/condensat/bank-core/database/model"
    13  
    14  	"github.com/jinzhu/gorm"
    15  )
    16  
    17  const (
    18  	DefaultBatchExecutionDelay time.Duration = time.Hour
    19  	DefaultBatchCapacity       model.Int     = 16
    20  )
    21  
    22  var (
    23  	ErrInvalidBatchID        = errors.New("Invalid BatchID")
    24  	ErrInvalidBatchWithdraws = errors.New("Invalid Withdraws")
    25  	ErrInvalidNetwork        = errors.New("Invalid Network")
    26  )
    27  
    28  func AddBatch(db database.Context, network model.BatchNetwork, data model.BatchData, withdraws ...model.WithdrawID) (model.Batch, error) {
    29  	gdb := db.DB().(*gorm.DB)
    30  	if db == nil {
    31  		return model.Batch{}, database.ErrInvalidDatabase
    32  	}
    33  
    34  	if len(network) == 0 {
    35  		return model.Batch{}, ErrInvalidNetwork
    36  	}
    37  
    38  	timestamp := time.Now().UTC().Truncate(time.Second)
    39  	result := model.Batch{
    40  		Timestamp:    timestamp,
    41  		ExecuteAfter: timestamp.Add(DefaultBatchExecutionDelay),
    42  		Capacity:     DefaultBatchCapacity,
    43  		Network:      network,
    44  		Data:         data,
    45  	}
    46  	err := gdb.Create(&result).Error
    47  	if err != nil {
    48  		return model.Batch{}, err
    49  	}
    50  
    51  	err = AddWithdrawToBatch(db, result.ID, withdraws...)
    52  	if err != nil {
    53  		return model.Batch{}, err
    54  	}
    55  
    56  	return result, nil
    57  }
    58  
    59  func GetBatch(db database.Context, ID model.BatchID) (model.Batch, error) {
    60  	gdb := db.DB().(*gorm.DB)
    61  	if db == nil {
    62  		return model.Batch{}, database.ErrInvalidDatabase
    63  	}
    64  
    65  	if ID == 0 {
    66  		return model.Batch{}, ErrInvalidBatchID
    67  	}
    68  
    69  	var result model.Batch
    70  	err := gdb.
    71  		Where(&model.Batch{ID: ID}).
    72  		First(&result).Error
    73  	if err != nil {
    74  		return model.Batch{}, err
    75  	}
    76  
    77  	return result, nil
    78  }
    79  
    80  func FetchBatchReady(db database.Context) ([]model.Batch, error) {
    81  	gdb := db.DB().(*gorm.DB)
    82  	if gdb == nil {
    83  		return nil, database.ErrInvalidDatabase
    84  	}
    85  
    86  	subQueryInfo := gdb.Model(&model.BatchInfo{}).
    87  		Where(model.BatchInfo{
    88  			Status: model.BatchStatusCreated,
    89  		}).
    90  		SubQuery()
    91  
    92  	subQueryLast := gdb.Model(&model.BatchInfo{}).
    93  		Select("MAX(id)").
    94  		Group("batch_id").
    95  		SubQuery()
    96  
    97  	var list []*model.Batch
    98  	err := gdb.Model(&model.Batch{}).
    99  		Joins("JOIN (?) AS i ON batch.id = i.batch_id", subQueryInfo).
   100  		Where("i.id IN (?)", subQueryLast).
   101  		Where("batch.execute_after <= ?", time.Now().UTC().Truncate(time.Second)).
   102  		Order("batch.id ASC").
   103  		Find(&list).Error
   104  
   105  	if err != nil && err != gorm.ErrRecordNotFound {
   106  		return nil, err
   107  	}
   108  	return convertBatchList(list), nil
   109  }
   110  
   111  func FetchBatchByLastStatus(db database.Context, status model.BatchStatus) ([]model.Batch, error) {
   112  	gdb := db.DB().(*gorm.DB)
   113  	if gdb == nil {
   114  		return nil, database.ErrInvalidDatabase
   115  	}
   116  
   117  	if len(status) == 0 {
   118  		return nil, ErrInvalidBatchStatus
   119  	}
   120  
   121  	subQueryInfo := gdb.Model(&model.BatchInfo{}).
   122  		Where(model.BatchInfo{
   123  			Status: status,
   124  		}).
   125  		SubQuery()
   126  
   127  	subQueryLast := gdb.Model(&model.BatchInfo{}).
   128  		Select("MAX(id)").
   129  		Group("batch_id").
   130  		SubQuery()
   131  
   132  	var list []*model.Batch
   133  	err := gdb.Model(&model.Batch{}).
   134  		Joins("JOIN (?) AS i ON batch.id = i.batch_id", subQueryInfo).
   135  		Where("i.id IN (?)", subQueryLast).
   136  		Order("batch.id ASC").
   137  		Find(&list).Error
   138  
   139  	if err != nil && err != gorm.ErrRecordNotFound {
   140  		return nil, err
   141  	}
   142  	return convertBatchList(list), nil
   143  }
   144  
   145  func ListBatchNetworksByStatus(db database.Context, status model.BatchStatus) ([]model.BatchNetwork, error) {
   146  	gdb := db.DB().(*gorm.DB)
   147  	if db == nil {
   148  		return nil, database.ErrInvalidDatabase
   149  	}
   150  
   151  	if len(status) == 0 {
   152  		return nil, ErrInvalidWithdrawStatus
   153  	}
   154  
   155  	subQueryInfo := gdb.Model(&model.BatchInfo{}).
   156  		Where(model.BatchInfo{
   157  			Status: status,
   158  		}).
   159  		SubQuery()
   160  
   161  	var list []*model.Batch
   162  	err := gdb.Model(&model.Batch{}).
   163  		Select("network").
   164  		Joins("JOIN (?) AS i ON batch.id = i.batch_id", subQueryInfo).
   165  		Group("network").
   166  		Order("batch.id ASC").
   167  		Find(&list).Error
   168  
   169  	if err != nil && err != gorm.ErrRecordNotFound {
   170  		return nil, err
   171  	}
   172  
   173  	return convertBatchNetworkList(list), nil
   174  }
   175  
   176  type BatchInfos struct {
   177  	Count  int
   178  	Active int
   179  }
   180  
   181  func BatchsInfos(db database.Context) (BatchInfos, error) {
   182  	gdb := db.DB().(*gorm.DB)
   183  	if gdb == nil {
   184  		return BatchInfos{}, database.ErrInvalidDatabase
   185  	}
   186  
   187  	var totalBatchs int64
   188  	err := gdb.Model(&model.Batch{}).
   189  		Count(&totalBatchs).Error
   190  	if err != nil {
   191  		return BatchInfos{}, err
   192  	}
   193  
   194  	subQueryLast := gdb.Model(&model.BatchInfo{}).
   195  		Select("MAX(id)").
   196  		Group("batch_id").
   197  		SubQuery()
   198  
   199  	var activeBatchs int64
   200  	err = gdb.Model(&model.BatchInfo{}).
   201  		Where("id IN (?)", subQueryLast).
   202  		Where("status <> ?", model.BatchStatusSettled).
   203  		Count(&activeBatchs).Error
   204  	if err != nil {
   205  		return BatchInfos{}, err
   206  	}
   207  
   208  	return BatchInfos{
   209  		Count:  int(totalBatchs),
   210  		Active: int(activeBatchs),
   211  	}, nil
   212  }
   213  
   214  func convertBatchList(list []*model.Batch) []model.Batch {
   215  	var result []model.Batch
   216  	for _, curr := range list {
   217  		if curr != nil {
   218  			result = append(result, *curr)
   219  		}
   220  	}
   221  
   222  	return result[:]
   223  }
   224  
   225  func convertBatchNetworkList(list []*model.Batch) []model.BatchNetwork {
   226  	var result []model.BatchNetwork
   227  	for _, curr := range list {
   228  		if curr != nil {
   229  			result = append(result, curr.Network)
   230  		}
   231  	}
   232  
   233  	return result[:]
   234  }