github.com/go-generalize/volcago@v1.7.0/generator/testfiles/auto/different_dir/lock_meta_gen.go (about)

     1  // Code generated by volcago. DO NOT EDIT.
     2  // generated version: (devel)
     3  package model
     4  
     5  import (
     6  	"context"
     7  	"time"
     8  
     9  	"cloud.google.com/go/firestore"
    10  	"golang.org/x/xerrors"
    11  	"google.golang.org/api/iterator"
    12  	"google.golang.org/grpc/codes"
    13  	"google.golang.org/grpc/status"
    14  
    15  	model "github.com/go-generalize/volcago/generator/testfiles/auto"
    16  )
    17  
    18  //go:generate mockgen -source $GOFILE -destination mock/mock_lock_meta_gen/mock_lock_meta_gen.go
    19  
    20  // LockMetaRepository - Repository of LockMeta
    21  type LockMetaRepository interface {
    22  	// Single
    23  	Get(ctx context.Context, id string, opts ...GetOption) (*model.LockMeta, error)
    24  	GetWithDoc(ctx context.Context, doc *firestore.DocumentRef, opts ...GetOption) (*model.LockMeta, error)
    25  	Insert(ctx context.Context, subject *model.LockMeta) (_ string, err error)
    26  	Update(ctx context.Context, subject *model.LockMeta) (err error)
    27  	StrictUpdate(ctx context.Context, id string, param *LockMetaUpdateParam, opts ...firestore.Precondition) error
    28  	Delete(ctx context.Context, subject *model.LockMeta, opts ...DeleteOption) (err error)
    29  	DeleteByID(ctx context.Context, id string, opts ...DeleteOption) (err error)
    30  	// Multiple
    31  	GetMulti(ctx context.Context, ids []string, opts ...GetOption) ([]*model.LockMeta, error)
    32  	InsertMulti(ctx context.Context, subjects []*model.LockMeta) (_ []string, er error)
    33  	UpdateMulti(ctx context.Context, subjects []*model.LockMeta) (er error)
    34  	DeleteMulti(ctx context.Context, subjects []*model.LockMeta, opts ...DeleteOption) (er error)
    35  	DeleteMultiByIDs(ctx context.Context, ids []string, opts ...DeleteOption) (er error)
    36  	// Single(Transaction)
    37  	GetWithTx(tx *firestore.Transaction, id string, opts ...GetOption) (*model.LockMeta, error)
    38  	GetWithDocWithTx(tx *firestore.Transaction, doc *firestore.DocumentRef, opts ...GetOption) (*model.LockMeta, error)
    39  	InsertWithTx(ctx context.Context, tx *firestore.Transaction, subject *model.LockMeta) (_ string, err error)
    40  	UpdateWithTx(ctx context.Context, tx *firestore.Transaction, subject *model.LockMeta) (err error)
    41  	StrictUpdateWithTx(tx *firestore.Transaction, id string, param *LockMetaUpdateParam, opts ...firestore.Precondition) error
    42  	DeleteWithTx(ctx context.Context, tx *firestore.Transaction, subject *model.LockMeta, opts ...DeleteOption) (err error)
    43  	DeleteByIDWithTx(ctx context.Context, tx *firestore.Transaction, id string, opts ...DeleteOption) (err error)
    44  	// Multiple(Transaction)
    45  	GetMultiWithTx(tx *firestore.Transaction, ids []string, opts ...GetOption) ([]*model.LockMeta, error)
    46  	InsertMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*model.LockMeta) (_ []string, er error)
    47  	UpdateMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*model.LockMeta) (er error)
    48  	DeleteMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*model.LockMeta, opts ...DeleteOption) (er error)
    49  	DeleteMultiByIDsWithTx(ctx context.Context, tx *firestore.Transaction, ids []string, opts ...DeleteOption) (er error)
    50  	// Search
    51  	Search(ctx context.Context, param *LockMetaSearchParam, q *firestore.Query) ([]*model.LockMeta, error)
    52  	SearchWithTx(tx *firestore.Transaction, param *LockMetaSearchParam, q *firestore.Query) ([]*model.LockMeta, error)
    53  	SearchByParam(ctx context.Context, param *LockMetaSearchParam) ([]*model.LockMeta, *PagingResult, error)
    54  	SearchByParamWithTx(tx *firestore.Transaction, param *LockMetaSearchParam) ([]*model.LockMeta, *PagingResult, error)
    55  	// misc
    56  	GetCollection() *firestore.CollectionRef
    57  	GetCollectionName() string
    58  	GetDocRef(id string) *firestore.DocumentRef
    59  	RunInTransaction() func(ctx context.Context, f func(context.Context, *firestore.Transaction) error, opts ...firestore.TransactionOption) (err error)
    60  }
    61  
    62  // LockMetaRepositoryMiddleware - middleware of LockMetaRepository
    63  type LockMetaRepositoryMiddleware interface {
    64  	BeforeInsert(ctx context.Context, subject *model.LockMeta) (bool, error)
    65  	BeforeUpdate(ctx context.Context, old, subject *model.LockMeta) (bool, error)
    66  	BeforeDelete(ctx context.Context, subject *model.LockMeta, opts ...DeleteOption) (bool, error)
    67  	BeforeDeleteByID(ctx context.Context, ids []string, opts ...DeleteOption) (bool, error)
    68  }
    69  
    70  type lockMetaRepository struct {
    71  	collectionName   string
    72  	firestoreClient  *firestore.Client
    73  	middleware       []LockMetaRepositoryMiddleware
    74  	uniqueRepository *uniqueRepository
    75  }
    76  
    77  // NewLockMetaRepository - constructor
    78  func NewLockMetaRepository(firestoreClient *firestore.Client, middleware ...LockMetaRepositoryMiddleware) LockMetaRepository {
    79  	return &lockMetaRepository{
    80  		collectionName:   "LockMeta",
    81  		firestoreClient:  firestoreClient,
    82  		middleware:       middleware,
    83  		uniqueRepository: newUniqueRepository(firestoreClient, "LockMeta"),
    84  	}
    85  }
    86  
    87  func (repo *lockMetaRepository) setMeta(subject *model.LockMeta, isInsert bool) {
    88  	now := time.Now()
    89  
    90  	if isInsert {
    91  		subject.CreatedAt = now
    92  	}
    93  	subject.UpdatedAt = now
    94  	subject.Version++
    95  }
    96  
    97  func (repo *lockMetaRepository) setMetaWithStrictUpdate(param *LockMetaUpdateParam) {
    98  	param.UpdatedAt = firestore.ServerTimestamp
    99  	param.Version = firestore.Increment(1)
   100  }
   101  
   102  func (repo *lockMetaRepository) beforeInsert(ctx context.Context, subject *model.LockMeta) error {
   103  	if subject.Version != 0 {
   104  		return xerrors.Errorf("insert data must be Version == 0 %+v: %w", subject, ErrVersionConflict)
   105  	}
   106  	if subject.DeletedAt != nil {
   107  		return xerrors.Errorf("insert data must be DeletedAt == nil: %+v", subject)
   108  	}
   109  	repo.setMeta(subject, true)
   110  	repo.uniqueRepository.setMiddleware(ctx)
   111  	err := repo.uniqueRepository.CheckUnique(ctx, nil, subject)
   112  	if err != nil {
   113  		return xerrors.Errorf("unique.middleware error: %w", err)
   114  	}
   115  
   116  	for _, m := range repo.middleware {
   117  		c, err := m.BeforeInsert(ctx, subject)
   118  		if err != nil {
   119  			return xerrors.Errorf("beforeInsert.middleware error: %w", err)
   120  		}
   121  		if !c {
   122  			continue
   123  		}
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  func (repo *lockMetaRepository) beforeUpdate(ctx context.Context, old, subject *model.LockMeta) error {
   130  	if ctx.Value(transactionInProgressKey{}) != nil && old == nil {
   131  		var err error
   132  		doc := repo.GetDocRef(subject.ID)
   133  		old, err = repo.get(context.Background(), doc)
   134  		if err != nil {
   135  			if status.Code(err) == codes.NotFound {
   136  				return ErrNotFound
   137  			}
   138  			return xerrors.Errorf("error in Get method: %w", err)
   139  		}
   140  	}
   141  	if old.Version > subject.Version {
   142  		return xerrors.Errorf(
   143  			"The data in the database is newer: (db version: %d, target version: %d) %+v: %w",
   144  			old.Version, subject.Version, subject, ErrVersionConflict,
   145  		)
   146  	}
   147  	if subject.DeletedAt != nil {
   148  		return xerrors.Errorf("update data must be DeletedAt == nil: %+v", subject)
   149  	}
   150  	repo.setMeta(subject, false)
   151  	repo.uniqueRepository.setMiddleware(ctx)
   152  	err := repo.uniqueRepository.CheckUnique(ctx, old, subject)
   153  	if err != nil {
   154  		return xerrors.Errorf("unique.middleware error: %w", err)
   155  	}
   156  
   157  	for _, m := range repo.middleware {
   158  		c, err := m.BeforeUpdate(ctx, old, subject)
   159  		if err != nil {
   160  			return xerrors.Errorf("beforeUpdate.middleware error: %w", err)
   161  		}
   162  		if !c {
   163  			continue
   164  		}
   165  	}
   166  
   167  	return nil
   168  }
   169  
   170  func (repo *lockMetaRepository) beforeDelete(ctx context.Context, subject *model.LockMeta, opts ...DeleteOption) error {
   171  	repo.setMeta(subject, false)
   172  	repo.uniqueRepository.setMiddleware(ctx)
   173  	err := repo.uniqueRepository.DeleteUnique(ctx, subject)
   174  	if err != nil {
   175  		return xerrors.Errorf("unique.middleware error: %w", err)
   176  	}
   177  
   178  	for _, m := range repo.middleware {
   179  		c, err := m.BeforeDelete(ctx, subject, opts...)
   180  		if err != nil {
   181  			return xerrors.Errorf("beforeDelete.middleware error: %w", err)
   182  		}
   183  		if !c {
   184  			continue
   185  		}
   186  	}
   187  
   188  	return nil
   189  }
   190  
   191  // GetCollection - *firestore.CollectionRef getter
   192  func (repo *lockMetaRepository) GetCollection() *firestore.CollectionRef {
   193  	return repo.firestoreClient.Collection(repo.collectionName)
   194  }
   195  
   196  // GetCollectionName - CollectionName getter
   197  func (repo *lockMetaRepository) GetCollectionName() string {
   198  	return repo.collectionName
   199  }
   200  
   201  // GetDocRef - *firestore.DocumentRef getter
   202  func (repo *lockMetaRepository) GetDocRef(id string) *firestore.DocumentRef {
   203  	return repo.GetCollection().Doc(id)
   204  }
   205  
   206  // RunInTransaction - (*firestore.Client).RunTransaction getter
   207  func (repo *lockMetaRepository) RunInTransaction() func(ctx context.Context, f func(context.Context, *firestore.Transaction) error, opts ...firestore.TransactionOption) (err error) {
   208  	return repo.firestoreClient.RunTransaction
   209  }
   210  
   211  // LockMetaSearchParam - params for search
   212  type LockMetaSearchParam struct {
   213  	ID        *QueryChainer
   214  	Text      *QueryChainer
   215  	Flag      *QueryChainer
   216  	CreatedAt *QueryChainer
   217  	CreatedBy *QueryChainer
   218  	UpdatedAt *QueryChainer
   219  	UpdatedBy *QueryChainer
   220  	DeletedAt *QueryChainer
   221  	DeletedBy *QueryChainer
   222  	Version   *QueryChainer
   223  
   224  	IncludeSoftDeleted bool
   225  	CursorKey          string
   226  	CursorLimit        int
   227  }
   228  
   229  // LockMetaUpdateParam - params for strict updates
   230  type LockMetaUpdateParam struct {
   231  	Text      interface{}
   232  	Flag      interface{}
   233  	CreatedAt interface{}
   234  	CreatedBy interface{}
   235  	UpdatedAt interface{}
   236  	UpdatedBy interface{}
   237  	DeletedAt interface{}
   238  	DeletedBy interface{}
   239  	Version   interface{}
   240  }
   241  
   242  // Search - search documents
   243  // The third argument is firestore.Query, basically you can pass nil
   244  func (repo *lockMetaRepository) Search(ctx context.Context, param *LockMetaSearchParam, q *firestore.Query) ([]*model.LockMeta, error) {
   245  	return repo.search(ctx, param, q)
   246  }
   247  
   248  // SearchByParam - search documents by search param
   249  func (repo *lockMetaRepository) SearchByParam(ctx context.Context, param *LockMetaSearchParam) ([]*model.LockMeta, *PagingResult, error) {
   250  	return repo.searchByParam(ctx, param)
   251  }
   252  
   253  // Get - get `LockMeta` by `LockMeta.ID`
   254  func (repo *lockMetaRepository) Get(ctx context.Context, id string, opts ...GetOption) (*model.LockMeta, error) {
   255  	doc := repo.GetDocRef(id)
   256  	return repo.get(ctx, doc, opts...)
   257  }
   258  
   259  // GetWithDoc - get `LockMeta` by *firestore.DocumentRef
   260  func (repo *lockMetaRepository) GetWithDoc(ctx context.Context, doc *firestore.DocumentRef, opts ...GetOption) (*model.LockMeta, error) {
   261  	return repo.get(ctx, doc, opts...)
   262  }
   263  
   264  // Insert - insert of `LockMeta`
   265  func (repo *lockMetaRepository) Insert(ctx context.Context, subject *model.LockMeta) (_ string, err error) {
   266  	if err := repo.beforeInsert(ctx, subject); err != nil {
   267  		return "", xerrors.Errorf("before insert error: %w", err)
   268  	}
   269  
   270  	return repo.insert(ctx, subject)
   271  }
   272  
   273  // Update - update of `LockMeta`
   274  func (repo *lockMetaRepository) Update(ctx context.Context, subject *model.LockMeta) (err error) {
   275  	doc := repo.GetDocRef(subject.ID)
   276  
   277  	old, err := repo.get(ctx, doc)
   278  	if err != nil {
   279  		if status.Code(err) == codes.NotFound {
   280  			return ErrNotFound
   281  		}
   282  		return xerrors.Errorf("error in Get method: %w", err)
   283  	}
   284  
   285  	if err := repo.beforeUpdate(ctx, old, subject); err != nil {
   286  		return xerrors.Errorf("before update error: %w", err)
   287  	}
   288  
   289  	return repo.update(ctx, subject)
   290  }
   291  
   292  // StrictUpdate - strict update of `LockMeta`
   293  func (repo *lockMetaRepository) StrictUpdate(ctx context.Context, id string, param *LockMetaUpdateParam, opts ...firestore.Precondition) error {
   294  	return repo.strictUpdate(ctx, id, param, opts...)
   295  }
   296  
   297  // Delete - delete of `LockMeta`
   298  func (repo *lockMetaRepository) Delete(ctx context.Context, subject *model.LockMeta, opts ...DeleteOption) (err error) {
   299  	if err := repo.beforeDelete(ctx, subject, opts...); err != nil {
   300  		return xerrors.Errorf("before delete error: %w", err)
   301  	}
   302  
   303  	if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   304  		t := time.Now()
   305  		subject.DeletedAt = &t
   306  		if err := repo.update(ctx, subject); err != nil {
   307  			return xerrors.Errorf("error in update method: %w", err)
   308  		}
   309  		return nil
   310  	}
   311  
   312  	return repo.deleteByID(ctx, subject.ID)
   313  }
   314  
   315  // DeleteByID - delete `LockMeta` by `LockMeta.ID`
   316  func (repo *lockMetaRepository) DeleteByID(ctx context.Context, id string, opts ...DeleteOption) (err error) {
   317  	subject, err := repo.Get(ctx, id)
   318  	if err != nil {
   319  		return xerrors.Errorf("error in Get method: %w", err)
   320  	}
   321  
   322  	if err := repo.beforeDelete(ctx, subject, opts...); err != nil {
   323  		return xerrors.Errorf("before delete error: %w", err)
   324  	}
   325  
   326  	if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   327  		t := time.Now()
   328  		subject.DeletedAt = &t
   329  		if err := repo.update(ctx, subject); err != nil {
   330  			return xerrors.Errorf("error in update method: %w", err)
   331  		}
   332  		return nil
   333  	}
   334  
   335  	return repo.Delete(ctx, subject, opts...)
   336  }
   337  
   338  // GetMulti - get `LockMeta` in bulk by array of `LockMeta.ID`
   339  func (repo *lockMetaRepository) GetMulti(ctx context.Context, ids []string, opts ...GetOption) ([]*model.LockMeta, error) {
   340  	return repo.getMulti(ctx, ids, opts...)
   341  }
   342  
   343  // InsertMulti - bulk insert of `LockMeta`
   344  func (repo *lockMetaRepository) InsertMulti(ctx context.Context, subjects []*model.LockMeta) (_ []string, er error) {
   345  
   346  	ids := make([]string, 0, len(subjects))
   347  	batches := make([]*firestore.WriteBatch, 0)
   348  	batch := repo.firestoreClient.Batch()
   349  	collect := repo.GetCollection()
   350  
   351  	for i, subject := range subjects {
   352  		var ref *firestore.DocumentRef
   353  		if subject.ID == "" {
   354  			ref = collect.NewDoc()
   355  			subject.ID = ref.ID
   356  		} else {
   357  			ref = collect.Doc(subject.ID)
   358  			if s, err := ref.Get(ctx); err == nil {
   359  				return nil, xerrors.Errorf("already exists [%v]: %#v", subject.ID, s)
   360  			}
   361  		}
   362  
   363  		if err := repo.beforeInsert(ctx, subject); err != nil {
   364  			return nil, xerrors.Errorf("before insert error(%d) [%v]: %w", i, subject.ID, err)
   365  		}
   366  
   367  		batch.Set(ref, subject)
   368  		ids = append(ids, ref.ID)
   369  		i++
   370  		if (i%500) == 0 && len(subjects) != i {
   371  			batches = append(batches, batch)
   372  			batch = repo.firestoreClient.Batch()
   373  		}
   374  	}
   375  	batches = append(batches, batch)
   376  
   377  	for _, b := range batches {
   378  		if _, err := b.Commit(ctx); err != nil {
   379  			return nil, xerrors.Errorf("error in Commit method: %w", err)
   380  		}
   381  	}
   382  
   383  	return ids, nil
   384  }
   385  
   386  // UpdateMulti - bulk update of `LockMeta`
   387  func (repo *lockMetaRepository) UpdateMulti(ctx context.Context, subjects []*model.LockMeta) (er error) {
   388  
   389  	batches := make([]*firestore.WriteBatch, 0)
   390  	batch := repo.firestoreClient.Batch()
   391  	collect := repo.GetCollection()
   392  
   393  	for i, subject := range subjects {
   394  		ref := collect.Doc(subject.ID)
   395  		snapShot, err := ref.Get(ctx)
   396  		if err != nil {
   397  			if status.Code(err) == codes.NotFound {
   398  				return xerrors.Errorf("not found [%v]: %w", subject.ID, err)
   399  			}
   400  			return xerrors.Errorf("error in Get method [%v]: %w", subject.ID, err)
   401  		}
   402  
   403  		old := new(model.LockMeta)
   404  		if err = snapShot.DataTo(&old); err != nil {
   405  			return xerrors.Errorf("error in DataTo method: %w", err)
   406  		}
   407  
   408  		if err := repo.beforeUpdate(ctx, old, subject); err != nil {
   409  			return xerrors.Errorf("before update error(%d) [%v]: %w", i, subject.ID, err)
   410  		}
   411  
   412  		batch.Set(ref, subject)
   413  		i++
   414  		if (i%500) == 0 && len(subjects) != i {
   415  			batches = append(batches, batch)
   416  			batch = repo.firestoreClient.Batch()
   417  		}
   418  	}
   419  	batches = append(batches, batch)
   420  
   421  	for _, b := range batches {
   422  		if _, err := b.Commit(ctx); err != nil {
   423  			return xerrors.Errorf("error in Commit method: %w", err)
   424  		}
   425  	}
   426  
   427  	return nil
   428  }
   429  
   430  // DeleteMulti - bulk delete of `LockMeta`
   431  func (repo *lockMetaRepository) DeleteMulti(ctx context.Context, subjects []*model.LockMeta, opts ...DeleteOption) (er error) {
   432  
   433  	batches := make([]*firestore.WriteBatch, 0)
   434  	batch := repo.firestoreClient.Batch()
   435  	collect := repo.GetCollection()
   436  
   437  	for i, subject := range subjects {
   438  		ref := collect.Doc(subject.ID)
   439  		if _, err := ref.Get(ctx); err != nil {
   440  			if status.Code(err) == codes.NotFound {
   441  				return xerrors.Errorf("not found [%v]: %w", subject.ID, err)
   442  			}
   443  			return xerrors.Errorf("error in Get method [%v]: %w", subject.ID, err)
   444  		}
   445  
   446  		if err := repo.beforeDelete(ctx, subject, opts...); err != nil {
   447  			return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subject.ID, err)
   448  		}
   449  
   450  		if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   451  			t := time.Now()
   452  			subject.DeletedAt = &t
   453  			batch.Set(ref, subject)
   454  		} else {
   455  			batch.Delete(ref)
   456  		}
   457  
   458  		i++
   459  		if (i%500) == 0 && len(subjects) != i {
   460  			batches = append(batches, batch)
   461  			batch = repo.firestoreClient.Batch()
   462  		}
   463  	}
   464  	batches = append(batches, batch)
   465  
   466  	for _, b := range batches {
   467  		if _, err := b.Commit(ctx); err != nil {
   468  			return xerrors.Errorf("error in Commit method: %w", err)
   469  		}
   470  	}
   471  
   472  	return nil
   473  }
   474  
   475  // DeleteMultiByIDs - delete `LockMeta` in bulk by array of `LockMeta.ID`
   476  func (repo *lockMetaRepository) DeleteMultiByIDs(ctx context.Context, ids []string, opts ...DeleteOption) (er error) {
   477  	subjects := make([]*model.LockMeta, len(ids))
   478  
   479  	opt := GetOption{}
   480  	if len(opts) > 0 {
   481  		opt.IncludeSoftDeleted = opts[0].Mode == DeleteModeHard
   482  	}
   483  	for i, id := range ids {
   484  		subject, err := repo.Get(ctx, id, opt)
   485  		if err != nil {
   486  			return xerrors.Errorf("error in Get method: %w", err)
   487  		}
   488  		subjects[i] = subject
   489  	}
   490  
   491  	return repo.DeleteMulti(ctx, subjects, opts...)
   492  }
   493  
   494  // SearchWithTx - search documents in transaction
   495  func (repo *lockMetaRepository) SearchWithTx(tx *firestore.Transaction, param *LockMetaSearchParam, q *firestore.Query) ([]*model.LockMeta, error) {
   496  	return repo.search(tx, param, q)
   497  }
   498  
   499  // SearchByParamWithTx - search documents by search param in transaction
   500  func (repo *lockMetaRepository) SearchByParamWithTx(tx *firestore.Transaction, param *LockMetaSearchParam) ([]*model.LockMeta, *PagingResult, error) {
   501  	return repo.searchByParam(tx, param)
   502  }
   503  
   504  // GetWithTx - get `LockMeta` by `LockMeta.ID` in transaction
   505  func (repo *lockMetaRepository) GetWithTx(tx *firestore.Transaction, id string, opts ...GetOption) (*model.LockMeta, error) {
   506  	doc := repo.GetDocRef(id)
   507  	return repo.get(tx, doc, opts...)
   508  }
   509  
   510  // GetWithDocWithTx - get `LockMeta` by *firestore.DocumentRef in transaction
   511  func (repo *lockMetaRepository) GetWithDocWithTx(tx *firestore.Transaction, doc *firestore.DocumentRef, opts ...GetOption) (*model.LockMeta, error) {
   512  	return repo.get(tx, doc, opts...)
   513  }
   514  
   515  // InsertWithTx - insert of `LockMeta` in transaction
   516  func (repo *lockMetaRepository) InsertWithTx(ctx context.Context, tx *firestore.Transaction, subject *model.LockMeta) (_ string, err error) {
   517  	if err := repo.beforeInsert(context.WithValue(ctx, transactionInProgressKey{}, tx), subject); err != nil {
   518  		return "", xerrors.Errorf("before insert error: %w", err)
   519  	}
   520  
   521  	return repo.insert(tx, subject)
   522  }
   523  
   524  // UpdateWithTx - update of `LockMeta` in transaction
   525  func (repo *lockMetaRepository) UpdateWithTx(ctx context.Context, tx *firestore.Transaction, subject *model.LockMeta) (err error) {
   526  	if err := repo.beforeUpdate(context.WithValue(ctx, transactionInProgressKey{}, tx), nil, subject); err != nil {
   527  		return xerrors.Errorf("before update error: %w", err)
   528  	}
   529  
   530  	return repo.update(tx, subject)
   531  }
   532  
   533  // StrictUpdateWithTx - strict update of `LockMeta` in transaction
   534  func (repo *lockMetaRepository) StrictUpdateWithTx(tx *firestore.Transaction, id string, param *LockMetaUpdateParam, opts ...firestore.Precondition) error {
   535  	return repo.strictUpdate(tx, id, param, opts...)
   536  }
   537  
   538  // DeleteWithTx - delete of `LockMeta` in transaction
   539  func (repo *lockMetaRepository) DeleteWithTx(ctx context.Context, tx *firestore.Transaction, subject *model.LockMeta, opts ...DeleteOption) (err error) {
   540  	if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil {
   541  		return xerrors.Errorf("before delete error: %w", err)
   542  	}
   543  
   544  	if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   545  		t := time.Now()
   546  		subject.DeletedAt = &t
   547  		if err := repo.update(tx, subject); err != nil {
   548  			return xerrors.Errorf("error in update method: %w", err)
   549  		}
   550  		return nil
   551  	}
   552  
   553  	return repo.deleteByID(tx, subject.ID)
   554  }
   555  
   556  // DeleteByIDWithTx - delete `LockMeta` by `LockMeta.ID` in transaction
   557  func (repo *lockMetaRepository) DeleteByIDWithTx(ctx context.Context, tx *firestore.Transaction, id string, opts ...DeleteOption) (err error) {
   558  	subject, err := repo.Get(context.Background(), id)
   559  	if err != nil {
   560  		return xerrors.Errorf("error in Get method: %w", err)
   561  	}
   562  
   563  	if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   564  		t := time.Now()
   565  		subject.DeletedAt = &t
   566  		if err := repo.update(tx, subject); err != nil {
   567  			return xerrors.Errorf("error in update method: %w", err)
   568  		}
   569  		return nil
   570  	}
   571  
   572  	if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil {
   573  		return xerrors.Errorf("before delete error: %w", err)
   574  	}
   575  
   576  	return repo.deleteByID(tx, id)
   577  }
   578  
   579  // GetMultiWithTx - get `LockMeta` in bulk by array of `LockMeta.ID` in transaction
   580  func (repo *lockMetaRepository) GetMultiWithTx(tx *firestore.Transaction, ids []string, opts ...GetOption) ([]*model.LockMeta, error) {
   581  	return repo.getMulti(tx, ids, opts...)
   582  }
   583  
   584  // InsertMultiWithTx - bulk insert of `LockMeta` in transaction
   585  func (repo *lockMetaRepository) InsertMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*model.LockMeta) (_ []string, er error) {
   586  
   587  	ids := make([]string, len(subjects))
   588  
   589  	for i := range subjects {
   590  		if err := repo.beforeInsert(ctx, subjects[i]); err != nil {
   591  			return nil, xerrors.Errorf("before insert error(%d) [%v]: %w", i, subjects[i].ID, err)
   592  		}
   593  
   594  		id, err := repo.insert(tx, subjects[i])
   595  		if err != nil {
   596  			return nil, xerrors.Errorf("error in insert method(%d) [%v]: %w", i, subjects[i].ID, err)
   597  		}
   598  		ids[i] = id
   599  	}
   600  
   601  	return ids, nil
   602  }
   603  
   604  // UpdateMultiWithTx - bulk update of `LockMeta` in transaction
   605  func (repo *lockMetaRepository) UpdateMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*model.LockMeta) (er error) {
   606  	ctx = context.WithValue(ctx, transactionInProgressKey{}, tx)
   607  
   608  	for i := range subjects {
   609  		if err := repo.beforeUpdate(ctx, nil, subjects[i]); err != nil {
   610  			return xerrors.Errorf("before update error(%d) [%v]: %w", i, subjects[i].ID, err)
   611  		}
   612  	}
   613  
   614  	for i := range subjects {
   615  		if err := repo.update(tx, subjects[i]); err != nil {
   616  			return xerrors.Errorf("error in update method(%d) [%v]: %w", i, subjects[i].ID, err)
   617  		}
   618  	}
   619  
   620  	return nil
   621  }
   622  
   623  // DeleteMultiWithTx - bulk delete of `LockMeta` in transaction
   624  func (repo *lockMetaRepository) DeleteMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*model.LockMeta, opts ...DeleteOption) (er error) {
   625  
   626  	t := time.Now()
   627  	var isHardDeleteMode bool
   628  	if len(opts) > 0 {
   629  		isHardDeleteMode = opts[0].Mode == DeleteModeHard
   630  	}
   631  	opt := GetOption{
   632  		IncludeSoftDeleted: isHardDeleteMode,
   633  	}
   634  	for i := range subjects {
   635  		dr := repo.GetDocRef(subjects[i].ID)
   636  		if _, err := repo.get(context.Background(), dr, opt); err != nil {
   637  			if status.Code(err) == codes.NotFound {
   638  				return xerrors.Errorf("not found(%d) [%v]", i, subjects[i].ID)
   639  			}
   640  			return xerrors.Errorf("error in get method(%d) [%v]: %w", i, subjects[i].ID, err)
   641  		}
   642  
   643  		if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subjects[i], opts...); err != nil {
   644  			return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subjects[i].ID, err)
   645  		}
   646  
   647  		if !isHardDeleteMode {
   648  			subjects[i].DeletedAt = &t
   649  			if err := repo.update(tx, subjects[i]); err != nil {
   650  				return xerrors.Errorf("error in update method(%d) [%v]: %w", i, subjects[i].ID, err)
   651  			}
   652  		}
   653  	}
   654  
   655  	if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   656  		return nil
   657  	}
   658  
   659  	for i := range subjects {
   660  		if err := repo.deleteByID(tx, subjects[i].ID); err != nil {
   661  			return xerrors.Errorf("error in delete method(%d) [%v]: %w", i, subjects[i].ID, err)
   662  		}
   663  	}
   664  
   665  	return nil
   666  }
   667  
   668  // DeleteMultiByIDWithTx - delete `LockMeta` in bulk by array of `LockMeta.ID` in transaction
   669  func (repo *lockMetaRepository) DeleteMultiByIDsWithTx(ctx context.Context, tx *firestore.Transaction, ids []string, opts ...DeleteOption) (er error) {
   670  
   671  	t := time.Now()
   672  	for i := range ids {
   673  		dr := repo.GetDocRef(ids[i])
   674  		subject, err := repo.get(context.Background(), dr)
   675  		if err != nil {
   676  			if status.Code(err) == codes.NotFound {
   677  				return xerrors.Errorf("not found(%d) [%v]", i, ids[i])
   678  			}
   679  			return xerrors.Errorf("error in get method(%d) [%v]: %w", i, ids[i], err)
   680  		}
   681  
   682  		if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil {
   683  			return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subject.ID, err)
   684  		}
   685  
   686  		if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   687  			subject.DeletedAt = &t
   688  			if err := repo.update(tx, subject); err != nil {
   689  				return xerrors.Errorf("error in update method(%d) [%v]: %w", i, ids[i], err)
   690  			}
   691  		}
   692  	}
   693  
   694  	if len(opts) > 0 && opts[0].Mode == DeleteModeSoft {
   695  		return nil
   696  	}
   697  
   698  	for i := range ids {
   699  		if err := repo.deleteByID(tx, ids[i]); err != nil {
   700  			return xerrors.Errorf("error in delete method(%d) [%v]: %w", i, ids[i], err)
   701  		}
   702  	}
   703  
   704  	return nil
   705  }
   706  
   707  func (repo *lockMetaRepository) get(v interface{}, doc *firestore.DocumentRef, opts ...GetOption) (*model.LockMeta, error) {
   708  	var (
   709  		snapShot *firestore.DocumentSnapshot
   710  		err      error
   711  	)
   712  
   713  	switch x := v.(type) {
   714  	case *firestore.Transaction:
   715  		snapShot, err = x.Get(doc)
   716  	case context.Context:
   717  		snapShot, err = doc.Get(x)
   718  	default:
   719  		return nil, xerrors.Errorf("invalid type: %v", x)
   720  	}
   721  
   722  	if err != nil {
   723  		if status.Code(err) == codes.NotFound {
   724  			return nil, ErrNotFound
   725  		}
   726  		return nil, xerrors.Errorf("error in Get method: %w", err)
   727  	}
   728  
   729  	subject := new(model.LockMeta)
   730  	if err := snapShot.DataTo(&subject); err != nil {
   731  		return nil, xerrors.Errorf("error in DataTo method: %w", err)
   732  	}
   733  
   734  	if len(opts) == 0 || !opts[0].IncludeSoftDeleted {
   735  		if subject.DeletedAt != nil {
   736  			return nil, ErrAlreadyDeleted
   737  		}
   738  	}
   739  	subject.ID = snapShot.Ref.ID
   740  
   741  	return subject, nil
   742  }
   743  
   744  func (repo *lockMetaRepository) getMulti(v interface{}, ids []string, opts ...GetOption) ([]*model.LockMeta, error) {
   745  	var (
   746  		snapShots []*firestore.DocumentSnapshot
   747  		err       error
   748  		collect   = repo.GetCollection()
   749  		drs       = make([]*firestore.DocumentRef, len(ids))
   750  	)
   751  
   752  	for i, id := range ids {
   753  		ref := collect.Doc(id)
   754  		drs[i] = ref
   755  	}
   756  
   757  	switch x := v.(type) {
   758  	case *firestore.Transaction:
   759  		snapShots, err = x.GetAll(drs)
   760  	case context.Context:
   761  		snapShots, err = repo.firestoreClient.GetAll(x, drs)
   762  	default:
   763  		return nil, xerrors.Errorf("invalid type: %v", v)
   764  	}
   765  
   766  	if err != nil {
   767  		return nil, xerrors.Errorf("error in GetAll method: %w", err)
   768  	}
   769  
   770  	subjects := make([]*model.LockMeta, 0, len(ids))
   771  	mErr := NewMultiErrors()
   772  	for i, snapShot := range snapShots {
   773  		if !snapShot.Exists() {
   774  			mErr = append(mErr, NewMultiError(i, ErrNotFound))
   775  			continue
   776  		}
   777  
   778  		subject := new(model.LockMeta)
   779  		if err = snapShot.DataTo(&subject); err != nil {
   780  			return nil, xerrors.Errorf("error in DataTo method: %w", err)
   781  		}
   782  
   783  		if len(opts) == 0 || !opts[0].IncludeSoftDeleted {
   784  			if subject.DeletedAt != nil {
   785  				mErr = append(mErr, NewMultiError(i, ErrLogicallyDeletedData))
   786  				continue
   787  			}
   788  		}
   789  		subject.ID = snapShot.Ref.ID
   790  		subjects = append(subjects, subject)
   791  	}
   792  
   793  	if len(mErr) == 0 {
   794  		return subjects, nil
   795  	}
   796  
   797  	return subjects, mErr
   798  }
   799  
   800  func (repo *lockMetaRepository) insert(v interface{}, subject *model.LockMeta) (string, error) {
   801  	var (
   802  		dr  = repo.GetCollection().NewDoc()
   803  		err error
   804  	)
   805  
   806  	switch x := v.(type) {
   807  	case *firestore.Transaction:
   808  		err = x.Create(dr, subject)
   809  	case context.Context:
   810  		_, err = dr.Create(x, subject)
   811  	default:
   812  		return "", xerrors.Errorf("invalid type: %v", v)
   813  	}
   814  
   815  	if err != nil {
   816  		if status.Code(err) == codes.AlreadyExists {
   817  			return "", xerrors.Errorf("error in Create method: err=%+v: %w", err, ErrAlreadyExists)
   818  		}
   819  		return "", xerrors.Errorf("error in Create method: %w", err)
   820  	}
   821  
   822  	subject.ID = dr.ID
   823  
   824  	return dr.ID, nil
   825  }
   826  
   827  func (repo *lockMetaRepository) update(v interface{}, subject *model.LockMeta) error {
   828  	var (
   829  		dr  = repo.GetDocRef(subject.ID)
   830  		err error
   831  	)
   832  
   833  	switch x := v.(type) {
   834  	case *firestore.Transaction:
   835  		err = x.Set(dr, subject)
   836  	case context.Context:
   837  		_, err = dr.Set(x, subject)
   838  	default:
   839  		return xerrors.Errorf("invalid type: %v", v)
   840  	}
   841  
   842  	if err != nil {
   843  		return xerrors.Errorf("error in Set method: %w", err)
   844  	}
   845  
   846  	return nil
   847  }
   848  
   849  func (repo *lockMetaRepository) strictUpdate(v interface{}, id string, param *LockMetaUpdateParam, opts ...firestore.Precondition) error {
   850  	var (
   851  		dr  = repo.GetDocRef(id)
   852  		err error
   853  	)
   854  
   855  	repo.setMetaWithStrictUpdate(param)
   856  
   857  	updates := updater(model.LockMeta{}, param)
   858  
   859  	switch x := v.(type) {
   860  	case *firestore.Transaction:
   861  		err = x.Update(dr, updates, opts...)
   862  	case context.Context:
   863  		_, err = dr.Update(x, updates, opts...)
   864  	default:
   865  		return xerrors.Errorf("invalid type: %v", v)
   866  	}
   867  
   868  	if err != nil {
   869  		return xerrors.Errorf("error in Update method: %w", err)
   870  	}
   871  
   872  	return nil
   873  }
   874  
   875  func (repo *lockMetaRepository) deleteByID(v interface{}, id string) error {
   876  	dr := repo.GetDocRef(id)
   877  	var err error
   878  
   879  	switch x := v.(type) {
   880  	case *firestore.Transaction:
   881  		err = x.Delete(dr, firestore.Exists)
   882  	case context.Context:
   883  		_, err = dr.Delete(x, firestore.Exists)
   884  	default:
   885  		return xerrors.Errorf("invalid type: %v", v)
   886  	}
   887  
   888  	if err != nil {
   889  		return xerrors.Errorf("error in Delete method: %w", err)
   890  	}
   891  
   892  	return nil
   893  }
   894  
   895  func (repo *lockMetaRepository) runQuery(v interface{}, query firestore.Query) ([]*model.LockMeta, error) {
   896  	var iter *firestore.DocumentIterator
   897  
   898  	switch x := v.(type) {
   899  	case *firestore.Transaction:
   900  		iter = x.Documents(query)
   901  	case context.Context:
   902  		iter = query.Documents(x)
   903  	default:
   904  		return nil, xerrors.Errorf("invalid type: %v", v)
   905  	}
   906  
   907  	defer iter.Stop()
   908  
   909  	subjects := make([]*model.LockMeta, 0)
   910  
   911  	for {
   912  		doc, err := iter.Next()
   913  		if err == iterator.Done {
   914  			break
   915  		}
   916  		if err != nil {
   917  			return nil, xerrors.Errorf("error in Next method: %w", err)
   918  		}
   919  
   920  		subject := new(model.LockMeta)
   921  
   922  		if err = doc.DataTo(&subject); err != nil {
   923  			return nil, xerrors.Errorf("error in DataTo method: %w", err)
   924  		}
   925  
   926  		subject.ID = doc.Ref.ID
   927  		subjects = append(subjects, subject)
   928  	}
   929  
   930  	return subjects, nil
   931  }
   932  
   933  // BUG(54m): there may be potential bugs
   934  func (repo *lockMetaRepository) searchByParam(v interface{}, param *LockMetaSearchParam) ([]*model.LockMeta, *PagingResult, error) {
   935  	query := func() firestore.Query {
   936  		return repo.GetCollection().Query
   937  	}()
   938  	if param.ID != nil {
   939  		for _, chain := range param.ID.QueryGroup {
   940  			var value interface{}
   941  			switch val := chain.Value.(type) {
   942  			case string:
   943  				value = repo.GetDocRef(val)
   944  			case []string:
   945  				docRefs := make([]*firestore.DocumentRef, len(val))
   946  				for i := range val {
   947  					docRefs[i] = repo.GetDocRef(val[i])
   948  				}
   949  				value = docRefs
   950  			default:
   951  				return nil, nil, xerrors.Errorf("document id can only be of type `string` and `[]string`. value: %#v", chain.Value)
   952  			}
   953  			query = query.Where(firestore.DocumentID, chain.Operator, value)
   954  		}
   955  		if direction := param.ID.OrderByDirection; direction > 0 {
   956  			query = query.OrderBy(firestore.DocumentID, direction)
   957  			query = param.ID.BuildCursorQuery(query)
   958  		}
   959  	}
   960  	if param.Text != nil {
   961  		for _, chain := range param.Text.QueryGroup {
   962  			query = query.Where("text", chain.Operator, chain.Value)
   963  		}
   964  		if direction := param.Text.OrderByDirection; direction > 0 {
   965  			query = query.OrderBy("text", direction)
   966  			query = param.Text.BuildCursorQuery(query)
   967  		}
   968  	}
   969  	if param.Flag != nil {
   970  		for _, chain := range param.Flag.QueryGroup {
   971  			items, ok := chain.Value.(map[string]float64)
   972  			if !ok {
   973  				continue
   974  			}
   975  			for key, value := range items {
   976  				query = query.WherePath(firestore.FieldPath{"flag", key}, chain.Operator, value)
   977  			}
   978  		}
   979  	}
   980  	if param.CreatedAt != nil {
   981  		for _, chain := range param.CreatedAt.QueryGroup {
   982  			query = query.Where("createdAt", chain.Operator, chain.Value)
   983  		}
   984  		if direction := param.CreatedAt.OrderByDirection; direction > 0 {
   985  			query = query.OrderBy("createdAt", direction)
   986  			query = param.CreatedAt.BuildCursorQuery(query)
   987  		}
   988  	}
   989  	if param.CreatedBy != nil {
   990  		for _, chain := range param.CreatedBy.QueryGroup {
   991  			query = query.Where("createdBy", chain.Operator, chain.Value)
   992  		}
   993  		if direction := param.CreatedBy.OrderByDirection; direction > 0 {
   994  			query = query.OrderBy("createdBy", direction)
   995  			query = param.CreatedBy.BuildCursorQuery(query)
   996  		}
   997  	}
   998  	if param.UpdatedAt != nil {
   999  		for _, chain := range param.UpdatedAt.QueryGroup {
  1000  			query = query.Where("updatedAt", chain.Operator, chain.Value)
  1001  		}
  1002  		if direction := param.UpdatedAt.OrderByDirection; direction > 0 {
  1003  			query = query.OrderBy("updatedAt", direction)
  1004  			query = param.UpdatedAt.BuildCursorQuery(query)
  1005  		}
  1006  	}
  1007  	if param.UpdatedBy != nil {
  1008  		for _, chain := range param.UpdatedBy.QueryGroup {
  1009  			query = query.Where("updatedBy", chain.Operator, chain.Value)
  1010  		}
  1011  		if direction := param.UpdatedBy.OrderByDirection; direction > 0 {
  1012  			query = query.OrderBy("updatedBy", direction)
  1013  			query = param.UpdatedBy.BuildCursorQuery(query)
  1014  		}
  1015  	}
  1016  	if param.DeletedAt != nil {
  1017  		for _, chain := range param.DeletedAt.QueryGroup {
  1018  			query = query.Where("deletedAt", chain.Operator, chain.Value)
  1019  		}
  1020  		if direction := param.DeletedAt.OrderByDirection; direction > 0 {
  1021  			query = query.OrderBy("deletedAt", direction)
  1022  			query = param.DeletedAt.BuildCursorQuery(query)
  1023  		}
  1024  	}
  1025  	if param.DeletedBy != nil {
  1026  		for _, chain := range param.DeletedBy.QueryGroup {
  1027  			query = query.Where("deletedBy", chain.Operator, chain.Value)
  1028  		}
  1029  		if direction := param.DeletedBy.OrderByDirection; direction > 0 {
  1030  			query = query.OrderBy("deletedBy", direction)
  1031  			query = param.DeletedBy.BuildCursorQuery(query)
  1032  		}
  1033  	}
  1034  	if param.Version != nil {
  1035  		for _, chain := range param.Version.QueryGroup {
  1036  			query = query.Where("version", chain.Operator, chain.Value)
  1037  		}
  1038  		if direction := param.Version.OrderByDirection; direction > 0 {
  1039  			query = query.OrderBy("version", direction)
  1040  			query = param.Version.BuildCursorQuery(query)
  1041  		}
  1042  	}
  1043  	if !param.IncludeSoftDeleted {
  1044  		query = query.Where("deletedAt", OpTypeEqual, nil)
  1045  	}
  1046  
  1047  	limit := param.CursorLimit + 1
  1048  
  1049  	if param.CursorKey != "" {
  1050  		var (
  1051  			ds  *firestore.DocumentSnapshot
  1052  			err error
  1053  		)
  1054  		switch x := v.(type) {
  1055  		case *firestore.Transaction:
  1056  			ds, err = x.Get(repo.GetDocRef(param.CursorKey))
  1057  		case context.Context:
  1058  			ds, err = repo.GetDocRef(param.CursorKey).Get(x)
  1059  		default:
  1060  			return nil, nil, xerrors.Errorf("invalid x type: %v", v)
  1061  		}
  1062  		if err != nil {
  1063  			if status.Code(err) == codes.NotFound {
  1064  				return nil, nil, ErrNotFound
  1065  			}
  1066  			return nil, nil, xerrors.Errorf("error in Get method: %w", err)
  1067  		}
  1068  		query = query.StartAt(ds)
  1069  	}
  1070  
  1071  	if limit > 1 {
  1072  		query = query.Limit(limit)
  1073  	}
  1074  
  1075  	subjects, err := repo.runQuery(v, query)
  1076  	if err != nil {
  1077  		return nil, nil, xerrors.Errorf("error in runQuery method: %w", err)
  1078  	}
  1079  
  1080  	pagingResult := &PagingResult{
  1081  		Length: len(subjects),
  1082  	}
  1083  	if limit > 1 && limit == pagingResult.Length {
  1084  		next := pagingResult.Length - 1
  1085  		pagingResult.NextCursorKey = subjects[next].ID
  1086  		subjects = subjects[:next]
  1087  		pagingResult.Length--
  1088  	}
  1089  
  1090  	return subjects, pagingResult, nil
  1091  }
  1092  
  1093  func (repo *lockMetaRepository) search(v interface{}, param *LockMetaSearchParam, q *firestore.Query) ([]*model.LockMeta, error) {
  1094  	if (param == nil && q == nil) || (param != nil && q != nil) {
  1095  		return nil, xerrors.New("either one should be nil")
  1096  	}
  1097  
  1098  	query := func() firestore.Query {
  1099  		if q != nil {
  1100  			return *q
  1101  		}
  1102  		return repo.GetCollection().Query
  1103  	}()
  1104  
  1105  	if q == nil {
  1106  		subjects, _, err := repo.searchByParam(v, param)
  1107  		if err != nil {
  1108  			return nil, xerrors.Errorf("error in searchByParam method: %w", err)
  1109  		}
  1110  
  1111  		return subjects, nil
  1112  	}
  1113  
  1114  	return repo.runQuery(v, query)
  1115  }