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